##// END OF EJS Templates
branchmap: server should not advertise secret changeset in branchmap (Issue3303)...
Pierre-Yves David -
r16535:39d1f83e stable
parent child Browse files
Show More
@@ -1,238 +1,241 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
10 import util, setdiscovery, treediscovery, phases
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 reponse lists justs
24 If you pass heads and they are all known locally, the reponse lists justs
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, commoninc=None):
89 def findcommonoutgoing(repo, other, onlyheads=None, force=False, commoninc=None):
90 '''Return an outgoing instance to identify the nodes present in repo but
90 '''Return an outgoing instance to identify the nodes present in repo but
91 not in other.
91 not in other.
92
92
93 If onlyheads is given, only nodes ancestral to nodes in onlyheads (inclusive)
93 If onlyheads is given, only nodes ancestral to nodes in onlyheads (inclusive)
94 are included. If you already know the local repo's heads, passing them in
94 are included. If you already know the local repo's heads, passing them in
95 onlyheads is faster than letting them be recomputed here.
95 onlyheads is faster than letting them be recomputed here.
96
96
97 If commoninc is given, it must the the result of a prior call to
97 If commoninc is given, it must the the result of a prior call to
98 findcommonincoming(repo, other, force) to avoid recomputing it here.'''
98 findcommonincoming(repo, other, force) to avoid recomputing it here.'''
99 # declare an empty outgoing object to be filled later
99 # declare an empty outgoing object to be filled later
100 og = outgoing(repo.changelog, None, None)
100 og = outgoing(repo.changelog, None, None)
101
101
102 # get common set if not provided
102 # get common set if not provided
103 if commoninc is None:
103 if commoninc is None:
104 commoninc = findcommonincoming(repo, other, force=force)
104 commoninc = findcommonincoming(repo, other, force=force)
105 og.commonheads, _any, _hds = commoninc
105 og.commonheads, _any, _hds = commoninc
106
106
107 # compute outgoing
107 # compute outgoing
108 if not repo._phaseroots[phases.secret]:
108 if not repo._phaseroots[phases.secret]:
109 og.missingheads = onlyheads or repo.heads()
109 og.missingheads = onlyheads or repo.heads()
110 elif onlyheads is None:
110 elif onlyheads is None:
111 # use visible heads as it should be cached
111 # use visible heads as it should be cached
112 og.missingheads = phases.visibleheads(repo)
112 og.missingheads = phases.visibleheads(repo)
113 og.excluded = [ctx.node() for ctx in repo.set('secret()')]
113 og.excluded = [ctx.node() for ctx in repo.set('secret()')]
114 else:
114 else:
115 # compute common, missing and exclude secret stuff
115 # compute common, missing and exclude secret stuff
116 sets = repo.changelog.findcommonmissing(og.commonheads, onlyheads)
116 sets = repo.changelog.findcommonmissing(og.commonheads, onlyheads)
117 og._common, allmissing = sets
117 og._common, allmissing = sets
118 og._missing = missing = []
118 og._missing = missing = []
119 og.excluded = excluded = []
119 og.excluded = excluded = []
120 for node in allmissing:
120 for node in allmissing:
121 if repo[node].phase() >= phases.secret:
121 if repo[node].phase() >= phases.secret:
122 excluded.append(node)
122 excluded.append(node)
123 else:
123 else:
124 missing.append(node)
124 missing.append(node)
125 if excluded:
125 if excluded:
126 # update missing heads
126 # update missing heads
127 missingheads = phases.newheads(repo, onlyheads, excluded)
127 missingheads = phases.newheads(repo, onlyheads, excluded)
128 else:
128 else:
129 missingheads = onlyheads
129 missingheads = onlyheads
130 og.missingheads = missingheads
130 og.missingheads = missingheads
131
131
132 return og
132 return og
133
133
134 def checkheads(repo, remote, outgoing, remoteheads, newbranch=False, inc=False):
134 def checkheads(repo, remote, outgoing, remoteheads, newbranch=False, inc=False):
135 """Check that a push won't add any outgoing head
135 """Check that a push won't add any outgoing head
136
136
137 raise Abort error and display ui message as needed.
137 raise Abort error and display ui message as needed.
138 """
138 """
139 if remoteheads == [nullid]:
139 if remoteheads == [nullid]:
140 # remote is empty, nothing to check.
140 # remote is empty, nothing to check.
141 return
141 return
142
142
143 cl = repo.changelog
143 cl = repo.changelog
144 if remote.capable('branchmap'):
144 if remote.capable('branchmap'):
145 # Check for each named branch if we're creating new remote heads.
145 # Check for each named branch if we're creating new remote heads.
146 # To be a remote head after push, node must be either:
146 # To be a remote head after push, node must be either:
147 # - unknown locally
147 # - unknown locally
148 # - a local outgoing head descended from update
148 # - a local outgoing head descended from update
149 # - a remote head that's known locally and not
149 # - a remote head that's known locally and not
150 # ancestral to an outgoing head
150 # ancestral to an outgoing head
151
151
152 # 1. Create set of branches involved in the push.
152 # 1. Create set of branches involved in the push.
153 branches = set(repo[n].branch() for n in outgoing.missing)
153 branches = set(repo[n].branch() for n in outgoing.missing)
154
154
155 # 2. Check for new branches on the remote.
155 # 2. Check for new branches on the remote.
156 remotemap = remote.branchmap()
156 if remote.local():
157 remotemap = phases.visiblebranchmap(remote)
158 else:
159 remotemap = remote.branchmap()
157 newbranches = branches - set(remotemap)
160 newbranches = branches - set(remotemap)
158 if newbranches and not newbranch: # new branch requires --new-branch
161 if newbranches and not newbranch: # new branch requires --new-branch
159 branchnames = ', '.join(sorted(newbranches))
162 branchnames = ', '.join(sorted(newbranches))
160 raise util.Abort(_("push creates new remote branches: %s!")
163 raise util.Abort(_("push creates new remote branches: %s!")
161 % branchnames,
164 % branchnames,
162 hint=_("use 'hg push --new-branch' to create"
165 hint=_("use 'hg push --new-branch' to create"
163 " new remote branches"))
166 " new remote branches"))
164 branches.difference_update(newbranches)
167 branches.difference_update(newbranches)
165
168
166 # 3. Construct the initial oldmap and newmap dicts.
169 # 3. Construct the initial oldmap and newmap dicts.
167 # They contain information about the remote heads before and
170 # They contain information about the remote heads before and
168 # after the push, respectively.
171 # after the push, respectively.
169 # Heads not found locally are not included in either dict,
172 # Heads not found locally are not included in either dict,
170 # since they won't be affected by the push.
173 # since they won't be affected by the push.
171 # unsynced contains all branches with incoming changesets.
174 # unsynced contains all branches with incoming changesets.
172 oldmap = {}
175 oldmap = {}
173 newmap = {}
176 newmap = {}
174 unsynced = set()
177 unsynced = set()
175 for branch in branches:
178 for branch in branches:
176 remotebrheads = remotemap[branch]
179 remotebrheads = remotemap[branch]
177 prunedbrheads = [h for h in remotebrheads if h in cl.nodemap]
180 prunedbrheads = [h for h in remotebrheads if h in cl.nodemap]
178 oldmap[branch] = prunedbrheads
181 oldmap[branch] = prunedbrheads
179 newmap[branch] = list(prunedbrheads)
182 newmap[branch] = list(prunedbrheads)
180 if len(remotebrheads) > len(prunedbrheads):
183 if len(remotebrheads) > len(prunedbrheads):
181 unsynced.add(branch)
184 unsynced.add(branch)
182
185
183 # 4. Update newmap with outgoing changes.
186 # 4. Update newmap with outgoing changes.
184 # This will possibly add new heads and remove existing ones.
187 # This will possibly add new heads and remove existing ones.
185 ctxgen = (repo[n] for n in outgoing.missing)
188 ctxgen = (repo[n] for n in outgoing.missing)
186 repo._updatebranchcache(newmap, ctxgen)
189 repo._updatebranchcache(newmap, ctxgen)
187
190
188 else:
191 else:
189 # 1-4b. old servers: Check for new topological heads.
192 # 1-4b. old servers: Check for new topological heads.
190 # Construct {old,new}map with branch = None (topological branch).
193 # Construct {old,new}map with branch = None (topological branch).
191 # (code based on _updatebranchcache)
194 # (code based on _updatebranchcache)
192 oldheads = set(h for h in remoteheads if h in cl.nodemap)
195 oldheads = set(h for h in remoteheads if h in cl.nodemap)
193 newheads = oldheads.union(outgoing.missing)
196 newheads = oldheads.union(outgoing.missing)
194 if len(newheads) > 1:
197 if len(newheads) > 1:
195 for latest in reversed(outgoing.missing):
198 for latest in reversed(outgoing.missing):
196 if latest not in newheads:
199 if latest not in newheads:
197 continue
200 continue
198 minhrev = min(cl.rev(h) for h in newheads)
201 minhrev = min(cl.rev(h) for h in newheads)
199 reachable = cl.reachable(latest, cl.node(minhrev))
202 reachable = cl.reachable(latest, cl.node(minhrev))
200 reachable.remove(latest)
203 reachable.remove(latest)
201 newheads.difference_update(reachable)
204 newheads.difference_update(reachable)
202 branches = set([None])
205 branches = set([None])
203 newmap = {None: newheads}
206 newmap = {None: newheads}
204 oldmap = {None: oldheads}
207 oldmap = {None: oldheads}
205 unsynced = inc and branches or set()
208 unsynced = inc and branches or set()
206
209
207 # 5. Check for new heads.
210 # 5. Check for new heads.
208 # If there are more heads after the push than before, a suitable
211 # If there are more heads after the push than before, a suitable
209 # error message, depending on unsynced status, is displayed.
212 # error message, depending on unsynced status, is displayed.
210 error = None
213 error = None
211 for branch in branches:
214 for branch in branches:
212 newhs = set(newmap[branch])
215 newhs = set(newmap[branch])
213 oldhs = set(oldmap[branch])
216 oldhs = set(oldmap[branch])
214 if len(newhs) > len(oldhs):
217 if len(newhs) > len(oldhs):
215 dhs = list(newhs - oldhs)
218 dhs = list(newhs - oldhs)
216 if error is None:
219 if error is None:
217 if branch not in ('default', None):
220 if branch not in ('default', None):
218 error = _("push creates new remote head %s "
221 error = _("push creates new remote head %s "
219 "on branch '%s'!") % (short(dhs[0]), branch)
222 "on branch '%s'!") % (short(dhs[0]), branch)
220 else:
223 else:
221 error = _("push creates new remote head %s!"
224 error = _("push creates new remote head %s!"
222 ) % short(dhs[0])
225 ) % short(dhs[0])
223 if branch in unsynced:
226 if branch in unsynced:
224 hint = _("you should pull and merge or "
227 hint = _("you should pull and merge or "
225 "use push -f to force")
228 "use push -f to force")
226 else:
229 else:
227 hint = _("did you forget to merge? "
230 hint = _("did you forget to merge? "
228 "use push -f to force")
231 "use push -f to force")
229 if branch is not None:
232 if branch is not None:
230 repo.ui.note(_("new remote heads on branch '%s'\n") % branch)
233 repo.ui.note(_("new remote heads on branch '%s'\n") % branch)
231 for h in dhs:
234 for h in dhs:
232 repo.ui.note(_("new remote head %s\n") % short(h))
235 repo.ui.note(_("new remote head %s\n") % short(h))
233 if error:
236 if error:
234 raise util.Abort(error, hint=hint)
237 raise util.Abort(error, hint=hint)
235
238
236 # 6. Check for unsynced changes on involved branches.
239 # 6. Check for unsynced changes on involved branches.
237 if unsynced:
240 if unsynced:
238 repo.ui.warn(_("note: unsynced remote changes!\n"))
241 repo.ui.warn(_("note: unsynced remote changes!\n"))
@@ -1,321 +1,343 b''
1 """ Mercurial phases support code
1 """ Mercurial phases support code
2
2
3 ---
3 ---
4
4
5 Copyright 2011 Pierre-Yves David <pierre-yves.david@ens-lyon.org>
5 Copyright 2011 Pierre-Yves David <pierre-yves.david@ens-lyon.org>
6 Logilab SA <contact@logilab.fr>
6 Logilab SA <contact@logilab.fr>
7 Augie Fackler <durin42@gmail.com>
7 Augie Fackler <durin42@gmail.com>
8
8
9 This software may be used and distributed according to the terms of the
9 This software may be used and distributed according to the terms of the
10 GNU General Public License version 2 or any later version.
10 GNU General Public License version 2 or any later version.
11
11
12 ---
12 ---
13
13
14 This module implements most phase logic in mercurial.
14 This module implements most phase logic in mercurial.
15
15
16
16
17 Basic Concept
17 Basic Concept
18 =============
18 =============
19
19
20 A 'changeset phases' is an indicator that tells us how a changeset is
20 A 'changeset phases' is an indicator that tells us how a changeset is
21 manipulated and communicated. The details of each phase is described below,
21 manipulated and communicated. The details of each phase is described below,
22 here we describe the properties they have in common.
22 here we describe the properties they have in common.
23
23
24 Like bookmarks, phases are not stored in history and thus are not permanent and
24 Like bookmarks, phases are not stored in history and thus are not permanent and
25 leave no audit trail.
25 leave no audit trail.
26
26
27 First, no changeset can be in two phases at once. Phases are ordered, so they
27 First, no changeset can be in two phases at once. Phases are ordered, so they
28 can be considered from lowest to highest. The default, lowest phase is 'public'
28 can be considered from lowest to highest. The default, lowest phase is 'public'
29 - this is the normal phase of existing changesets. A child changeset can not be
29 - this is the normal phase of existing changesets. A child changeset can not be
30 in a lower phase than its parents.
30 in a lower phase than its parents.
31
31
32 These phases share a hierarchy of traits:
32 These phases share a hierarchy of traits:
33
33
34 immutable shared
34 immutable shared
35 public: X X
35 public: X X
36 draft: X
36 draft: X
37 secret:
37 secret:
38
38
39 local commits are draft by default
39 local commits are draft by default
40
40
41 Phase movement and exchange
41 Phase movement and exchange
42 ============================
42 ============================
43
43
44 Phase data are exchanged by pushkey on pull and push. Some server have a
44 Phase data are exchanged by pushkey on pull and push. Some server have a
45 publish option set, we call them publishing server. Pushing to such server make
45 publish option set, we call them publishing server. Pushing to such server make
46 draft changeset publish.
46 draft changeset publish.
47
47
48 A small list of fact/rules define the exchange of phase:
48 A small list of fact/rules define the exchange of phase:
49
49
50 * old client never changes server states
50 * old client never changes server states
51 * pull never changes server states
51 * pull never changes server states
52 * publish and old server csets are seen as public by client
52 * publish and old server csets are seen as public by client
53
53
54 * Any secret changeset seens in another repository is lowered to at least draft
54 * Any secret changeset seens in another repository is lowered to at least draft
55
55
56
56
57 Here is the final table summing up the 49 possible usecase of phase exchange:
57 Here is the final table summing up the 49 possible usecase of phase exchange:
58
58
59 server
59 server
60 old publish non-publish
60 old publish non-publish
61 N X N D P N D P
61 N X N D P N D P
62 old client
62 old client
63 pull
63 pull
64 N - X/X - X/D X/P - X/D X/P
64 N - X/X - X/D X/P - X/D X/P
65 X - X/X - X/D X/P - X/D X/P
65 X - X/X - X/D X/P - X/D X/P
66 push
66 push
67 X X/X X/X X/P X/P X/P X/D X/D X/P
67 X X/X X/X X/P X/P X/P X/D X/D X/P
68 new client
68 new client
69 pull
69 pull
70 N - P/X - P/D P/P - D/D P/P
70 N - P/X - P/D P/P - D/D P/P
71 D - P/X - P/D P/P - D/D P/P
71 D - P/X - P/D P/P - D/D P/P
72 P - P/X - P/D P/P - P/D P/P
72 P - P/X - P/D P/P - P/D P/P
73 push
73 push
74 D P/X P/X P/P P/P P/P D/D D/D P/P
74 D P/X P/X P/P P/P P/P D/D D/D P/P
75 P P/X P/X P/P P/P P/P P/P P/P P/P
75 P P/X P/X P/P P/P P/P P/P P/P P/P
76
76
77 Legend:
77 Legend:
78
78
79 A/B = final state on client / state on server
79 A/B = final state on client / state on server
80
80
81 * N = new/not present,
81 * N = new/not present,
82 * P = public,
82 * P = public,
83 * D = draft,
83 * D = draft,
84 * X = not tracked (ie: the old client or server has no internal way of
84 * X = not tracked (ie: the old client or server has no internal way of
85 recording the phase.)
85 recording the phase.)
86
86
87 passive = only pushes
87 passive = only pushes
88
88
89
89
90 A cell here can be read like this:
90 A cell here can be read like this:
91
91
92 "When a new client pushes a draft changeset (D) to a publishing server
92 "When a new client pushes a draft changeset (D) to a publishing server
93 where it's not present (N), it's marked public on both sides (P/P)."
93 where it's not present (N), it's marked public on both sides (P/P)."
94
94
95 Note: old client behave as publish server with Draft only content
95 Note: old client behave as publish server with Draft only content
96 - other people see it as public
96 - other people see it as public
97 - content is pushed as draft
97 - content is pushed as draft
98
98
99 """
99 """
100
100
101 import errno
101 import errno
102 from node import nullid, bin, hex, short
102 from node import nullid, bin, hex, short
103 from i18n import _
103 from i18n import _
104
104
105 allphases = public, draft, secret = range(3)
105 allphases = public, draft, secret = range(3)
106 trackedphases = allphases[1:]
106 trackedphases = allphases[1:]
107 phasenames = ['public', 'draft', 'secret']
107 phasenames = ['public', 'draft', 'secret']
108
108
109 def readroots(repo):
109 def readroots(repo):
110 """Read phase roots from disk"""
110 """Read phase roots from disk"""
111 roots = [set() for i in allphases]
111 roots = [set() for i in allphases]
112 try:
112 try:
113 f = repo.sopener('phaseroots')
113 f = repo.sopener('phaseroots')
114 try:
114 try:
115 for line in f:
115 for line in f:
116 phase, nh = line.strip().split()
116 phase, nh = line.strip().split()
117 roots[int(phase)].add(bin(nh))
117 roots[int(phase)].add(bin(nh))
118 finally:
118 finally:
119 f.close()
119 f.close()
120 except IOError, inst:
120 except IOError, inst:
121 if inst.errno != errno.ENOENT:
121 if inst.errno != errno.ENOENT:
122 raise
122 raise
123 for f in repo._phasedefaults:
123 for f in repo._phasedefaults:
124 roots = f(repo, roots)
124 roots = f(repo, roots)
125 repo._dirtyphases = True
125 repo._dirtyphases = True
126 return roots
126 return roots
127
127
128 def writeroots(repo):
128 def writeroots(repo):
129 """Write phase roots from disk"""
129 """Write phase roots from disk"""
130 f = repo.sopener('phaseroots', 'w', atomictemp=True)
130 f = repo.sopener('phaseroots', 'w', atomictemp=True)
131 try:
131 try:
132 for phase, roots in enumerate(repo._phaseroots):
132 for phase, roots in enumerate(repo._phaseroots):
133 for h in roots:
133 for h in roots:
134 f.write('%i %s\n' % (phase, hex(h)))
134 f.write('%i %s\n' % (phase, hex(h)))
135 repo._dirtyphases = False
135 repo._dirtyphases = False
136 finally:
136 finally:
137 f.close()
137 f.close()
138
138
139 def filterunknown(repo, phaseroots=None):
139 def filterunknown(repo, phaseroots=None):
140 """remove unknown nodes from the phase boundary
140 """remove unknown nodes from the phase boundary
141
141
142 no data is lost as unknown node only old data for their descentants
142 no data is lost as unknown node only old data for their descentants
143 """
143 """
144 if phaseroots is None:
144 if phaseroots is None:
145 phaseroots = repo._phaseroots
145 phaseroots = repo._phaseroots
146 nodemap = repo.changelog.nodemap # to filter unknown nodes
146 nodemap = repo.changelog.nodemap # to filter unknown nodes
147 for phase, nodes in enumerate(phaseroots):
147 for phase, nodes in enumerate(phaseroots):
148 missing = [node for node in nodes if node not in nodemap]
148 missing = [node for node in nodes if node not in nodemap]
149 if missing:
149 if missing:
150 for mnode in missing:
150 for mnode in missing:
151 repo.ui.debug(
151 repo.ui.debug(
152 'removing unknown node %s from %i-phase boundary\n'
152 'removing unknown node %s from %i-phase boundary\n'
153 % (short(mnode), phase))
153 % (short(mnode), phase))
154 nodes.symmetric_difference_update(missing)
154 nodes.symmetric_difference_update(missing)
155 repo._dirtyphases = True
155 repo._dirtyphases = True
156
156
157 def advanceboundary(repo, targetphase, nodes):
157 def advanceboundary(repo, targetphase, nodes):
158 """Add nodes to a phase changing other nodes phases if necessary.
158 """Add nodes to a phase changing other nodes phases if necessary.
159
159
160 This function move boundary *forward* this means that all nodes are set
160 This function move boundary *forward* this means that all nodes are set
161 in the target phase or kept in a *lower* phase.
161 in the target phase or kept in a *lower* phase.
162
162
163 Simplify boundary to contains phase roots only."""
163 Simplify boundary to contains phase roots only."""
164 delroots = [] # set of root deleted by this path
164 delroots = [] # set of root deleted by this path
165 for phase in xrange(targetphase + 1, len(allphases)):
165 for phase in xrange(targetphase + 1, len(allphases)):
166 # filter nodes that are not in a compatible phase already
166 # filter nodes that are not in a compatible phase already
167 # XXX rev phase cache might have been invalidated by a previous loop
167 # XXX rev phase cache might have been invalidated by a previous loop
168 # XXX we need to be smarter here
168 # XXX we need to be smarter here
169 nodes = [n for n in nodes if repo[n].phase() >= phase]
169 nodes = [n for n in nodes if repo[n].phase() >= phase]
170 if not nodes:
170 if not nodes:
171 break # no roots to move anymore
171 break # no roots to move anymore
172 roots = repo._phaseroots[phase]
172 roots = repo._phaseroots[phase]
173 olds = roots.copy()
173 olds = roots.copy()
174 ctxs = list(repo.set('roots((%ln::) - (%ln::%ln))', olds, olds, nodes))
174 ctxs = list(repo.set('roots((%ln::) - (%ln::%ln))', olds, olds, nodes))
175 roots.clear()
175 roots.clear()
176 roots.update(ctx.node() for ctx in ctxs)
176 roots.update(ctx.node() for ctx in ctxs)
177 if olds != roots:
177 if olds != roots:
178 # invalidate cache (we probably could be smarter here
178 # invalidate cache (we probably could be smarter here
179 if '_phaserev' in vars(repo):
179 if '_phaserev' in vars(repo):
180 del repo._phaserev
180 del repo._phaserev
181 repo._dirtyphases = True
181 repo._dirtyphases = True
182 # some roots may need to be declared for lower phases
182 # some roots may need to be declared for lower phases
183 delroots.extend(olds - roots)
183 delroots.extend(olds - roots)
184 # declare deleted root in the target phase
184 # declare deleted root in the target phase
185 if targetphase != 0:
185 if targetphase != 0:
186 retractboundary(repo, targetphase, delroots)
186 retractboundary(repo, targetphase, delroots)
187
187
188
188
189 def retractboundary(repo, targetphase, nodes):
189 def retractboundary(repo, targetphase, nodes):
190 """Set nodes back to a phase changing other nodes phases if necessary.
190 """Set nodes back to a phase changing other nodes phases if necessary.
191
191
192 This function move boundary *backward* this means that all nodes are set
192 This function move boundary *backward* this means that all nodes are set
193 in the target phase or kept in a *higher* phase.
193 in the target phase or kept in a *higher* phase.
194
194
195 Simplify boundary to contains phase roots only."""
195 Simplify boundary to contains phase roots only."""
196 currentroots = repo._phaseroots[targetphase]
196 currentroots = repo._phaseroots[targetphase]
197 newroots = [n for n in nodes if repo[n].phase() < targetphase]
197 newroots = [n for n in nodes if repo[n].phase() < targetphase]
198 if newroots:
198 if newroots:
199 currentroots.update(newroots)
199 currentroots.update(newroots)
200 ctxs = repo.set('roots(%ln::)', currentroots)
200 ctxs = repo.set('roots(%ln::)', currentroots)
201 currentroots.intersection_update(ctx.node() for ctx in ctxs)
201 currentroots.intersection_update(ctx.node() for ctx in ctxs)
202 if '_phaserev' in vars(repo):
202 if '_phaserev' in vars(repo):
203 del repo._phaserev
203 del repo._phaserev
204 repo._dirtyphases = True
204 repo._dirtyphases = True
205
205
206
206
207 def listphases(repo):
207 def listphases(repo):
208 """List phases root for serialisation over pushkey"""
208 """List phases root for serialisation over pushkey"""
209 keys = {}
209 keys = {}
210 value = '%i' % draft
210 value = '%i' % draft
211 for root in repo._phaseroots[draft]:
211 for root in repo._phaseroots[draft]:
212 keys[hex(root)] = value
212 keys[hex(root)] = value
213
213
214 if repo.ui.configbool('phases', 'publish', True):
214 if repo.ui.configbool('phases', 'publish', True):
215 # Add an extra data to let remote know we are a publishing repo.
215 # Add an extra data to let remote know we are a publishing repo.
216 # Publishing repo can't just pretend they are old repo. When pushing to
216 # Publishing repo can't just pretend they are old repo. When pushing to
217 # a publishing repo, the client still need to push phase boundary
217 # a publishing repo, the client still need to push phase boundary
218 #
218 #
219 # Push do not only push changeset. It also push phase data. New
219 # Push do not only push changeset. It also push phase data. New
220 # phase data may apply to common changeset which won't be push (as they
220 # phase data may apply to common changeset which won't be push (as they
221 # are common). Here is a very simple example:
221 # are common). Here is a very simple example:
222 #
222 #
223 # 1) repo A push changeset X as draft to repo B
223 # 1) repo A push changeset X as draft to repo B
224 # 2) repo B make changeset X public
224 # 2) repo B make changeset X public
225 # 3) repo B push to repo A. X is not pushed but the data that X as now
225 # 3) repo B push to repo A. X is not pushed but the data that X as now
226 # public should
226 # public should
227 #
227 #
228 # The server can't handle it on it's own as it has no idea of client
228 # The server can't handle it on it's own as it has no idea of client
229 # phase data.
229 # phase data.
230 keys['publishing'] = 'True'
230 keys['publishing'] = 'True'
231 return keys
231 return keys
232
232
233 def pushphase(repo, nhex, oldphasestr, newphasestr):
233 def pushphase(repo, nhex, oldphasestr, newphasestr):
234 """List phases root for serialisation over pushkey"""
234 """List phases root for serialisation over pushkey"""
235 lock = repo.lock()
235 lock = repo.lock()
236 try:
236 try:
237 currentphase = repo[nhex].phase()
237 currentphase = repo[nhex].phase()
238 newphase = abs(int(newphasestr)) # let's avoid negative index surprise
238 newphase = abs(int(newphasestr)) # let's avoid negative index surprise
239 oldphase = abs(int(oldphasestr)) # let's avoid negative index surprise
239 oldphase = abs(int(oldphasestr)) # let's avoid negative index surprise
240 if currentphase == oldphase and newphase < oldphase:
240 if currentphase == oldphase and newphase < oldphase:
241 advanceboundary(repo, newphase, [bin(nhex)])
241 advanceboundary(repo, newphase, [bin(nhex)])
242 return 1
242 return 1
243 elif currentphase == newphase:
243 elif currentphase == newphase:
244 # raced, but got correct result
244 # raced, but got correct result
245 return 1
245 return 1
246 else:
246 else:
247 return 0
247 return 0
248 finally:
248 finally:
249 lock.release()
249 lock.release()
250
250
251 def visibleheads(repo):
251 def visibleheads(repo):
252 """return the set of visible head of this repo"""
252 """return the set of visible head of this repo"""
253 # XXX we want a cache on this
253 # XXX we want a cache on this
254 sroots = repo._phaseroots[secret]
254 sroots = repo._phaseroots[secret]
255 if sroots:
255 if sroots:
256 # XXX very slow revset. storing heads or secret "boundary" would help.
256 # XXX very slow revset. storing heads or secret "boundary" would help.
257 revset = repo.set('heads(not (%ln::))', sroots)
257 revset = repo.set('heads(not (%ln::))', sroots)
258
258
259 vheads = [ctx.node() for ctx in revset]
259 vheads = [ctx.node() for ctx in revset]
260 if not vheads:
260 if not vheads:
261 vheads.append(nullid)
261 vheads.append(nullid)
262 else:
262 else:
263 vheads = repo.heads()
263 vheads = repo.heads()
264 return vheads
264 return vheads
265
265
266 def visiblebranchmap(repo):
267 """return a branchmap for the visible set"""
268 # XXX Recomputing this data on the fly is very slow. We should build a
269 # XXX cached version while computin the standard branchmap version.
270 sroots = repo._phaseroots[secret]
271 if sroots:
272 vbranchmap = {}
273 for branch, nodes in repo.branchmap().iteritems():
274 # search for secret heads.
275 for n in nodes:
276 if repo[n].phase() >= secret:
277 nodes = None
278 break
279 # if secreat heads where found we must compute them again
280 if nodes is None:
281 s = repo.set('heads(branch(%s) - secret())', branch)
282 nodes = [c.node() for c in s]
283 vbranchmap[branch] = nodes
284 else:
285 vbranchmap = repo.branchmap()
286 return vbranchmap
287
266 def analyzeremotephases(repo, subset, roots):
288 def analyzeremotephases(repo, subset, roots):
267 """Compute phases heads and root in a subset of node from root dict
289 """Compute phases heads and root in a subset of node from root dict
268
290
269 * subset is heads of the subset
291 * subset is heads of the subset
270 * roots is {<nodeid> => phase} mapping. key and value are string.
292 * roots is {<nodeid> => phase} mapping. key and value are string.
271
293
272 Accept unknown element input
294 Accept unknown element input
273 """
295 """
274 # build list from dictionary
296 # build list from dictionary
275 draftroots = []
297 draftroots = []
276 nodemap = repo.changelog.nodemap # to filter unknown nodes
298 nodemap = repo.changelog.nodemap # to filter unknown nodes
277 for nhex, phase in roots.iteritems():
299 for nhex, phase in roots.iteritems():
278 if nhex == 'publishing': # ignore data related to publish option
300 if nhex == 'publishing': # ignore data related to publish option
279 continue
301 continue
280 node = bin(nhex)
302 node = bin(nhex)
281 phase = int(phase)
303 phase = int(phase)
282 if phase == 0:
304 if phase == 0:
283 if node != nullid:
305 if node != nullid:
284 repo.ui.warn(_('ignoring inconsistent public root'
306 repo.ui.warn(_('ignoring inconsistent public root'
285 ' from remote: %s\n') % nhex)
307 ' from remote: %s\n') % nhex)
286 elif phase == 1:
308 elif phase == 1:
287 if node in nodemap:
309 if node in nodemap:
288 draftroots.append(node)
310 draftroots.append(node)
289 else:
311 else:
290 repo.ui.warn(_('ignoring unexpected root from remote: %i %s\n')
312 repo.ui.warn(_('ignoring unexpected root from remote: %i %s\n')
291 % (phase, nhex))
313 % (phase, nhex))
292 # compute heads
314 # compute heads
293 publicheads = newheads(repo, subset, draftroots)
315 publicheads = newheads(repo, subset, draftroots)
294 return publicheads, draftroots
316 return publicheads, draftroots
295
317
296 def newheads(repo, heads, roots):
318 def newheads(repo, heads, roots):
297 """compute new head of a subset minus another
319 """compute new head of a subset minus another
298
320
299 * `heads`: define the first subset
321 * `heads`: define the first subset
300 * `rroots`: define the second we substract to the first"""
322 * `rroots`: define the second we substract to the first"""
301 revset = repo.set('heads((%ln + parents(%ln)) - (%ln::%ln))',
323 revset = repo.set('heads((%ln + parents(%ln)) - (%ln::%ln))',
302 heads, roots, roots, heads)
324 heads, roots, roots, heads)
303 return [c.node() for c in revset]
325 return [c.node() for c in revset]
304
326
305
327
306 def newcommitphase(ui):
328 def newcommitphase(ui):
307 """helper to get the target phase of new commit
329 """helper to get the target phase of new commit
308
330
309 Handle all possible values for the phases.new-commit options.
331 Handle all possible values for the phases.new-commit options.
310
332
311 """
333 """
312 v = ui.config('phases', 'new-commit', draft)
334 v = ui.config('phases', 'new-commit', draft)
313 try:
335 try:
314 return phasenames.index(v)
336 return phasenames.index(v)
315 except ValueError:
337 except ValueError:
316 try:
338 try:
317 return int(v)
339 return int(v)
318 except ValueError:
340 except ValueError:
319 msg = _("phases.new-commit: not a valid phase name ('%s')")
341 msg = _("phases.new-commit: not a valid phase name ('%s')")
320 raise error.ConfigError(msg % v)
342 raise error.ConfigError(msg % v)
321
343
@@ -1,616 +1,616 b''
1 # wireproto.py - generic wire protocol support functions
1 # wireproto.py - generic wire protocol support functions
2 #
2 #
3 # Copyright 2005-2010 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-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 import urllib, tempfile, os, sys
8 import urllib, tempfile, os, sys
9 from i18n import _
9 from i18n import _
10 from node import bin, hex
10 from node import bin, hex
11 import changegroup as changegroupmod
11 import changegroup as changegroupmod
12 import repo, error, encoding, util, store
12 import repo, error, encoding, util, store
13 import phases
13 import phases
14
14
15 # abstract batching support
15 # abstract batching support
16
16
17 class future(object):
17 class future(object):
18 '''placeholder for a value to be set later'''
18 '''placeholder for a value to be set later'''
19 def set(self, value):
19 def set(self, value):
20 if util.safehasattr(self, 'value'):
20 if util.safehasattr(self, 'value'):
21 raise error.RepoError("future is already set")
21 raise error.RepoError("future is already set")
22 self.value = value
22 self.value = value
23
23
24 class batcher(object):
24 class batcher(object):
25 '''base class for batches of commands submittable in a single request
25 '''base class for batches of commands submittable in a single request
26
26
27 All methods invoked on instances of this class are simply queued and return a
27 All methods invoked on instances of this class are simply queued and return a
28 a future for the result. Once you call submit(), all the queued calls are
28 a future for the result. Once you call submit(), all the queued calls are
29 performed and the results set in their respective futures.
29 performed and the results set in their respective futures.
30 '''
30 '''
31 def __init__(self):
31 def __init__(self):
32 self.calls = []
32 self.calls = []
33 def __getattr__(self, name):
33 def __getattr__(self, name):
34 def call(*args, **opts):
34 def call(*args, **opts):
35 resref = future()
35 resref = future()
36 self.calls.append((name, args, opts, resref,))
36 self.calls.append((name, args, opts, resref,))
37 return resref
37 return resref
38 return call
38 return call
39 def submit(self):
39 def submit(self):
40 pass
40 pass
41
41
42 class localbatch(batcher):
42 class localbatch(batcher):
43 '''performs the queued calls directly'''
43 '''performs the queued calls directly'''
44 def __init__(self, local):
44 def __init__(self, local):
45 batcher.__init__(self)
45 batcher.__init__(self)
46 self.local = local
46 self.local = local
47 def submit(self):
47 def submit(self):
48 for name, args, opts, resref in self.calls:
48 for name, args, opts, resref in self.calls:
49 resref.set(getattr(self.local, name)(*args, **opts))
49 resref.set(getattr(self.local, name)(*args, **opts))
50
50
51 class remotebatch(batcher):
51 class remotebatch(batcher):
52 '''batches the queued calls; uses as few roundtrips as possible'''
52 '''batches the queued calls; uses as few roundtrips as possible'''
53 def __init__(self, remote):
53 def __init__(self, remote):
54 '''remote must support _submitbatch(encbatch) and _submitone(op, encargs)'''
54 '''remote must support _submitbatch(encbatch) and _submitone(op, encargs)'''
55 batcher.__init__(self)
55 batcher.__init__(self)
56 self.remote = remote
56 self.remote = remote
57 def submit(self):
57 def submit(self):
58 req, rsp = [], []
58 req, rsp = [], []
59 for name, args, opts, resref in self.calls:
59 for name, args, opts, resref in self.calls:
60 mtd = getattr(self.remote, name)
60 mtd = getattr(self.remote, name)
61 batchablefn = getattr(mtd, 'batchable', None)
61 batchablefn = getattr(mtd, 'batchable', None)
62 if batchablefn is not None:
62 if batchablefn is not None:
63 batchable = batchablefn(mtd.im_self, *args, **opts)
63 batchable = batchablefn(mtd.im_self, *args, **opts)
64 encargsorres, encresref = batchable.next()
64 encargsorres, encresref = batchable.next()
65 if encresref:
65 if encresref:
66 req.append((name, encargsorres,))
66 req.append((name, encargsorres,))
67 rsp.append((batchable, encresref, resref,))
67 rsp.append((batchable, encresref, resref,))
68 else:
68 else:
69 resref.set(encargsorres)
69 resref.set(encargsorres)
70 else:
70 else:
71 if req:
71 if req:
72 self._submitreq(req, rsp)
72 self._submitreq(req, rsp)
73 req, rsp = [], []
73 req, rsp = [], []
74 resref.set(mtd(*args, **opts))
74 resref.set(mtd(*args, **opts))
75 if req:
75 if req:
76 self._submitreq(req, rsp)
76 self._submitreq(req, rsp)
77 def _submitreq(self, req, rsp):
77 def _submitreq(self, req, rsp):
78 encresults = self.remote._submitbatch(req)
78 encresults = self.remote._submitbatch(req)
79 for encres, r in zip(encresults, rsp):
79 for encres, r in zip(encresults, rsp):
80 batchable, encresref, resref = r
80 batchable, encresref, resref = r
81 encresref.set(encres)
81 encresref.set(encres)
82 resref.set(batchable.next())
82 resref.set(batchable.next())
83
83
84 def batchable(f):
84 def batchable(f):
85 '''annotation for batchable methods
85 '''annotation for batchable methods
86
86
87 Such methods must implement a coroutine as follows:
87 Such methods must implement a coroutine as follows:
88
88
89 @batchable
89 @batchable
90 def sample(self, one, two=None):
90 def sample(self, one, two=None):
91 # Handle locally computable results first:
91 # Handle locally computable results first:
92 if not one:
92 if not one:
93 yield "a local result", None
93 yield "a local result", None
94 # Build list of encoded arguments suitable for your wire protocol:
94 # Build list of encoded arguments suitable for your wire protocol:
95 encargs = [('one', encode(one),), ('two', encode(two),)]
95 encargs = [('one', encode(one),), ('two', encode(two),)]
96 # Create future for injection of encoded result:
96 # Create future for injection of encoded result:
97 encresref = future()
97 encresref = future()
98 # Return encoded arguments and future:
98 # Return encoded arguments and future:
99 yield encargs, encresref
99 yield encargs, encresref
100 # Assuming the future to be filled with the result from the batched request
100 # Assuming the future to be filled with the result from the batched request
101 # now. Decode it:
101 # now. Decode it:
102 yield decode(encresref.value)
102 yield decode(encresref.value)
103
103
104 The decorator returns a function which wraps this coroutine as a plain method,
104 The decorator returns a function which wraps this coroutine as a plain method,
105 but adds the original method as an attribute called "batchable", which is
105 but adds the original method as an attribute called "batchable", which is
106 used by remotebatch to split the call into separate encoding and decoding
106 used by remotebatch to split the call into separate encoding and decoding
107 phases.
107 phases.
108 '''
108 '''
109 def plain(*args, **opts):
109 def plain(*args, **opts):
110 batchable = f(*args, **opts)
110 batchable = f(*args, **opts)
111 encargsorres, encresref = batchable.next()
111 encargsorres, encresref = batchable.next()
112 if not encresref:
112 if not encresref:
113 return encargsorres # a local result in this case
113 return encargsorres # a local result in this case
114 self = args[0]
114 self = args[0]
115 encresref.set(self._submitone(f.func_name, encargsorres))
115 encresref.set(self._submitone(f.func_name, encargsorres))
116 return batchable.next()
116 return batchable.next()
117 setattr(plain, 'batchable', f)
117 setattr(plain, 'batchable', f)
118 return plain
118 return plain
119
119
120 # list of nodes encoding / decoding
120 # list of nodes encoding / decoding
121
121
122 def decodelist(l, sep=' '):
122 def decodelist(l, sep=' '):
123 if l:
123 if l:
124 return map(bin, l.split(sep))
124 return map(bin, l.split(sep))
125 return []
125 return []
126
126
127 def encodelist(l, sep=' '):
127 def encodelist(l, sep=' '):
128 return sep.join(map(hex, l))
128 return sep.join(map(hex, l))
129
129
130 # batched call argument encoding
130 # batched call argument encoding
131
131
132 def escapearg(plain):
132 def escapearg(plain):
133 return (plain
133 return (plain
134 .replace(':', '::')
134 .replace(':', '::')
135 .replace(',', ':,')
135 .replace(',', ':,')
136 .replace(';', ':;')
136 .replace(';', ':;')
137 .replace('=', ':='))
137 .replace('=', ':='))
138
138
139 def unescapearg(escaped):
139 def unescapearg(escaped):
140 return (escaped
140 return (escaped
141 .replace(':=', '=')
141 .replace(':=', '=')
142 .replace(':;', ';')
142 .replace(':;', ';')
143 .replace(':,', ',')
143 .replace(':,', ',')
144 .replace('::', ':'))
144 .replace('::', ':'))
145
145
146 # client side
146 # client side
147
147
148 def todict(**args):
148 def todict(**args):
149 return args
149 return args
150
150
151 class wirerepository(repo.repository):
151 class wirerepository(repo.repository):
152
152
153 def batch(self):
153 def batch(self):
154 return remotebatch(self)
154 return remotebatch(self)
155 def _submitbatch(self, req):
155 def _submitbatch(self, req):
156 cmds = []
156 cmds = []
157 for op, argsdict in req:
157 for op, argsdict in req:
158 args = ','.join('%s=%s' % p for p in argsdict.iteritems())
158 args = ','.join('%s=%s' % p for p in argsdict.iteritems())
159 cmds.append('%s %s' % (op, args))
159 cmds.append('%s %s' % (op, args))
160 rsp = self._call("batch", cmds=';'.join(cmds))
160 rsp = self._call("batch", cmds=';'.join(cmds))
161 return rsp.split(';')
161 return rsp.split(';')
162 def _submitone(self, op, args):
162 def _submitone(self, op, args):
163 return self._call(op, **args)
163 return self._call(op, **args)
164
164
165 @batchable
165 @batchable
166 def lookup(self, key):
166 def lookup(self, key):
167 self.requirecap('lookup', _('look up remote revision'))
167 self.requirecap('lookup', _('look up remote revision'))
168 f = future()
168 f = future()
169 yield todict(key=encoding.fromlocal(key)), f
169 yield todict(key=encoding.fromlocal(key)), f
170 d = f.value
170 d = f.value
171 success, data = d[:-1].split(" ", 1)
171 success, data = d[:-1].split(" ", 1)
172 if int(success):
172 if int(success):
173 yield bin(data)
173 yield bin(data)
174 self._abort(error.RepoError(data))
174 self._abort(error.RepoError(data))
175
175
176 @batchable
176 @batchable
177 def heads(self):
177 def heads(self):
178 f = future()
178 f = future()
179 yield {}, f
179 yield {}, f
180 d = f.value
180 d = f.value
181 try:
181 try:
182 yield decodelist(d[:-1])
182 yield decodelist(d[:-1])
183 except ValueError:
183 except ValueError:
184 self._abort(error.ResponseError(_("unexpected response:"), d))
184 self._abort(error.ResponseError(_("unexpected response:"), d))
185
185
186 @batchable
186 @batchable
187 def known(self, nodes):
187 def known(self, nodes):
188 f = future()
188 f = future()
189 yield todict(nodes=encodelist(nodes)), f
189 yield todict(nodes=encodelist(nodes)), f
190 d = f.value
190 d = f.value
191 try:
191 try:
192 yield [bool(int(f)) for f in d]
192 yield [bool(int(f)) for f in d]
193 except ValueError:
193 except ValueError:
194 self._abort(error.ResponseError(_("unexpected response:"), d))
194 self._abort(error.ResponseError(_("unexpected response:"), d))
195
195
196 @batchable
196 @batchable
197 def branchmap(self):
197 def branchmap(self):
198 f = future()
198 f = future()
199 yield {}, f
199 yield {}, f
200 d = f.value
200 d = f.value
201 try:
201 try:
202 branchmap = {}
202 branchmap = {}
203 for branchpart in d.splitlines():
203 for branchpart in d.splitlines():
204 branchname, branchheads = branchpart.split(' ', 1)
204 branchname, branchheads = branchpart.split(' ', 1)
205 branchname = encoding.tolocal(urllib.unquote(branchname))
205 branchname = encoding.tolocal(urllib.unquote(branchname))
206 branchheads = decodelist(branchheads)
206 branchheads = decodelist(branchheads)
207 branchmap[branchname] = branchheads
207 branchmap[branchname] = branchheads
208 yield branchmap
208 yield branchmap
209 except TypeError:
209 except TypeError:
210 self._abort(error.ResponseError(_("unexpected response:"), d))
210 self._abort(error.ResponseError(_("unexpected response:"), d))
211
211
212 def branches(self, nodes):
212 def branches(self, nodes):
213 n = encodelist(nodes)
213 n = encodelist(nodes)
214 d = self._call("branches", nodes=n)
214 d = self._call("branches", nodes=n)
215 try:
215 try:
216 br = [tuple(decodelist(b)) for b in d.splitlines()]
216 br = [tuple(decodelist(b)) for b in d.splitlines()]
217 return br
217 return br
218 except ValueError:
218 except ValueError:
219 self._abort(error.ResponseError(_("unexpected response:"), d))
219 self._abort(error.ResponseError(_("unexpected response:"), d))
220
220
221 def between(self, pairs):
221 def between(self, pairs):
222 batch = 8 # avoid giant requests
222 batch = 8 # avoid giant requests
223 r = []
223 r = []
224 for i in xrange(0, len(pairs), batch):
224 for i in xrange(0, len(pairs), batch):
225 n = " ".join([encodelist(p, '-') for p in pairs[i:i + batch]])
225 n = " ".join([encodelist(p, '-') for p in pairs[i:i + batch]])
226 d = self._call("between", pairs=n)
226 d = self._call("between", pairs=n)
227 try:
227 try:
228 r.extend(l and decodelist(l) or [] for l in d.splitlines())
228 r.extend(l and decodelist(l) or [] for l in d.splitlines())
229 except ValueError:
229 except ValueError:
230 self._abort(error.ResponseError(_("unexpected response:"), d))
230 self._abort(error.ResponseError(_("unexpected response:"), d))
231 return r
231 return r
232
232
233 @batchable
233 @batchable
234 def pushkey(self, namespace, key, old, new):
234 def pushkey(self, namespace, key, old, new):
235 if not self.capable('pushkey'):
235 if not self.capable('pushkey'):
236 yield False, None
236 yield False, None
237 f = future()
237 f = future()
238 yield todict(namespace=encoding.fromlocal(namespace),
238 yield todict(namespace=encoding.fromlocal(namespace),
239 key=encoding.fromlocal(key),
239 key=encoding.fromlocal(key),
240 old=encoding.fromlocal(old),
240 old=encoding.fromlocal(old),
241 new=encoding.fromlocal(new)), f
241 new=encoding.fromlocal(new)), f
242 d = f.value
242 d = f.value
243 d, output = d.split('\n', 1)
243 d, output = d.split('\n', 1)
244 try:
244 try:
245 d = bool(int(d))
245 d = bool(int(d))
246 except ValueError:
246 except ValueError:
247 raise error.ResponseError(
247 raise error.ResponseError(
248 _('push failed (unexpected response):'), d)
248 _('push failed (unexpected response):'), d)
249 for l in output.splitlines(True):
249 for l in output.splitlines(True):
250 self.ui.status(_('remote: '), l)
250 self.ui.status(_('remote: '), l)
251 yield d
251 yield d
252
252
253 @batchable
253 @batchable
254 def listkeys(self, namespace):
254 def listkeys(self, namespace):
255 if not self.capable('pushkey'):
255 if not self.capable('pushkey'):
256 yield {}, None
256 yield {}, None
257 f = future()
257 f = future()
258 yield todict(namespace=encoding.fromlocal(namespace)), f
258 yield todict(namespace=encoding.fromlocal(namespace)), f
259 d = f.value
259 d = f.value
260 r = {}
260 r = {}
261 for l in d.splitlines():
261 for l in d.splitlines():
262 k, v = l.split('\t')
262 k, v = l.split('\t')
263 r[encoding.tolocal(k)] = encoding.tolocal(v)
263 r[encoding.tolocal(k)] = encoding.tolocal(v)
264 yield r
264 yield r
265
265
266 def stream_out(self):
266 def stream_out(self):
267 return self._callstream('stream_out')
267 return self._callstream('stream_out')
268
268
269 def changegroup(self, nodes, kind):
269 def changegroup(self, nodes, kind):
270 n = encodelist(nodes)
270 n = encodelist(nodes)
271 f = self._callstream("changegroup", roots=n)
271 f = self._callstream("changegroup", roots=n)
272 return changegroupmod.unbundle10(self._decompress(f), 'UN')
272 return changegroupmod.unbundle10(self._decompress(f), 'UN')
273
273
274 def changegroupsubset(self, bases, heads, kind):
274 def changegroupsubset(self, bases, heads, kind):
275 self.requirecap('changegroupsubset', _('look up remote changes'))
275 self.requirecap('changegroupsubset', _('look up remote changes'))
276 bases = encodelist(bases)
276 bases = encodelist(bases)
277 heads = encodelist(heads)
277 heads = encodelist(heads)
278 f = self._callstream("changegroupsubset",
278 f = self._callstream("changegroupsubset",
279 bases=bases, heads=heads)
279 bases=bases, heads=heads)
280 return changegroupmod.unbundle10(self._decompress(f), 'UN')
280 return changegroupmod.unbundle10(self._decompress(f), 'UN')
281
281
282 def getbundle(self, source, heads=None, common=None):
282 def getbundle(self, source, heads=None, common=None):
283 self.requirecap('getbundle', _('look up remote changes'))
283 self.requirecap('getbundle', _('look up remote changes'))
284 opts = {}
284 opts = {}
285 if heads is not None:
285 if heads is not None:
286 opts['heads'] = encodelist(heads)
286 opts['heads'] = encodelist(heads)
287 if common is not None:
287 if common is not None:
288 opts['common'] = encodelist(common)
288 opts['common'] = encodelist(common)
289 f = self._callstream("getbundle", **opts)
289 f = self._callstream("getbundle", **opts)
290 return changegroupmod.unbundle10(self._decompress(f), 'UN')
290 return changegroupmod.unbundle10(self._decompress(f), 'UN')
291
291
292 def unbundle(self, cg, heads, source):
292 def unbundle(self, cg, heads, source):
293 '''Send cg (a readable file-like object representing the
293 '''Send cg (a readable file-like object representing the
294 changegroup to push, typically a chunkbuffer object) to the
294 changegroup to push, typically a chunkbuffer object) to the
295 remote server as a bundle. Return an integer indicating the
295 remote server as a bundle. Return an integer indicating the
296 result of the push (see localrepository.addchangegroup()).'''
296 result of the push (see localrepository.addchangegroup()).'''
297
297
298 if heads != ['force'] and self.capable('unbundlehash'):
298 if heads != ['force'] and self.capable('unbundlehash'):
299 heads = encodelist(['hashed',
299 heads = encodelist(['hashed',
300 util.sha1(''.join(sorted(heads))).digest()])
300 util.sha1(''.join(sorted(heads))).digest()])
301 else:
301 else:
302 heads = encodelist(heads)
302 heads = encodelist(heads)
303
303
304 ret, output = self._callpush("unbundle", cg, heads=heads)
304 ret, output = self._callpush("unbundle", cg, heads=heads)
305 if ret == "":
305 if ret == "":
306 raise error.ResponseError(
306 raise error.ResponseError(
307 _('push failed:'), output)
307 _('push failed:'), output)
308 try:
308 try:
309 ret = int(ret)
309 ret = int(ret)
310 except ValueError:
310 except ValueError:
311 raise error.ResponseError(
311 raise error.ResponseError(
312 _('push failed (unexpected response):'), ret)
312 _('push failed (unexpected response):'), ret)
313
313
314 for l in output.splitlines(True):
314 for l in output.splitlines(True):
315 self.ui.status(_('remote: '), l)
315 self.ui.status(_('remote: '), l)
316 return ret
316 return ret
317
317
318 def debugwireargs(self, one, two, three=None, four=None, five=None):
318 def debugwireargs(self, one, two, three=None, four=None, five=None):
319 # don't pass optional arguments left at their default value
319 # don't pass optional arguments left at their default value
320 opts = {}
320 opts = {}
321 if three is not None:
321 if three is not None:
322 opts['three'] = three
322 opts['three'] = three
323 if four is not None:
323 if four is not None:
324 opts['four'] = four
324 opts['four'] = four
325 return self._call('debugwireargs', one=one, two=two, **opts)
325 return self._call('debugwireargs', one=one, two=two, **opts)
326
326
327 # server side
327 # server side
328
328
329 class streamres(object):
329 class streamres(object):
330 def __init__(self, gen):
330 def __init__(self, gen):
331 self.gen = gen
331 self.gen = gen
332
332
333 class pushres(object):
333 class pushres(object):
334 def __init__(self, res):
334 def __init__(self, res):
335 self.res = res
335 self.res = res
336
336
337 class pusherr(object):
337 class pusherr(object):
338 def __init__(self, res):
338 def __init__(self, res):
339 self.res = res
339 self.res = res
340
340
341 class ooberror(object):
341 class ooberror(object):
342 def __init__(self, message):
342 def __init__(self, message):
343 self.message = message
343 self.message = message
344
344
345 def dispatch(repo, proto, command):
345 def dispatch(repo, proto, command):
346 func, spec = commands[command]
346 func, spec = commands[command]
347 args = proto.getargs(spec)
347 args = proto.getargs(spec)
348 return func(repo, proto, *args)
348 return func(repo, proto, *args)
349
349
350 def options(cmd, keys, others):
350 def options(cmd, keys, others):
351 opts = {}
351 opts = {}
352 for k in keys:
352 for k in keys:
353 if k in others:
353 if k in others:
354 opts[k] = others[k]
354 opts[k] = others[k]
355 del others[k]
355 del others[k]
356 if others:
356 if others:
357 sys.stderr.write("abort: %s got unexpected arguments %s\n"
357 sys.stderr.write("abort: %s got unexpected arguments %s\n"
358 % (cmd, ",".join(others)))
358 % (cmd, ",".join(others)))
359 return opts
359 return opts
360
360
361 def batch(repo, proto, cmds, others):
361 def batch(repo, proto, cmds, others):
362 res = []
362 res = []
363 for pair in cmds.split(';'):
363 for pair in cmds.split(';'):
364 op, args = pair.split(' ', 1)
364 op, args = pair.split(' ', 1)
365 vals = {}
365 vals = {}
366 for a in args.split(','):
366 for a in args.split(','):
367 if a:
367 if a:
368 n, v = a.split('=')
368 n, v = a.split('=')
369 vals[n] = unescapearg(v)
369 vals[n] = unescapearg(v)
370 func, spec = commands[op]
370 func, spec = commands[op]
371 if spec:
371 if spec:
372 keys = spec.split()
372 keys = spec.split()
373 data = {}
373 data = {}
374 for k in keys:
374 for k in keys:
375 if k == '*':
375 if k == '*':
376 star = {}
376 star = {}
377 for key in vals.keys():
377 for key in vals.keys():
378 if key not in keys:
378 if key not in keys:
379 star[key] = vals[key]
379 star[key] = vals[key]
380 data['*'] = star
380 data['*'] = star
381 else:
381 else:
382 data[k] = vals[k]
382 data[k] = vals[k]
383 result = func(repo, proto, *[data[k] for k in keys])
383 result = func(repo, proto, *[data[k] for k in keys])
384 else:
384 else:
385 result = func(repo, proto)
385 result = func(repo, proto)
386 if isinstance(result, ooberror):
386 if isinstance(result, ooberror):
387 return result
387 return result
388 res.append(escapearg(result))
388 res.append(escapearg(result))
389 return ';'.join(res)
389 return ';'.join(res)
390
390
391 def between(repo, proto, pairs):
391 def between(repo, proto, pairs):
392 pairs = [decodelist(p, '-') for p in pairs.split(" ")]
392 pairs = [decodelist(p, '-') for p in pairs.split(" ")]
393 r = []
393 r = []
394 for b in repo.between(pairs):
394 for b in repo.between(pairs):
395 r.append(encodelist(b) + "\n")
395 r.append(encodelist(b) + "\n")
396 return "".join(r)
396 return "".join(r)
397
397
398 def branchmap(repo, proto):
398 def branchmap(repo, proto):
399 branchmap = repo.branchmap()
399 branchmap = phases.visiblebranchmap(repo)
400 heads = []
400 heads = []
401 for branch, nodes in branchmap.iteritems():
401 for branch, nodes in branchmap.iteritems():
402 branchname = urllib.quote(encoding.fromlocal(branch))
402 branchname = urllib.quote(encoding.fromlocal(branch))
403 branchnodes = encodelist(nodes)
403 branchnodes = encodelist(nodes)
404 heads.append('%s %s' % (branchname, branchnodes))
404 heads.append('%s %s' % (branchname, branchnodes))
405 return '\n'.join(heads)
405 return '\n'.join(heads)
406
406
407 def branches(repo, proto, nodes):
407 def branches(repo, proto, nodes):
408 nodes = decodelist(nodes)
408 nodes = decodelist(nodes)
409 r = []
409 r = []
410 for b in repo.branches(nodes):
410 for b in repo.branches(nodes):
411 r.append(encodelist(b) + "\n")
411 r.append(encodelist(b) + "\n")
412 return "".join(r)
412 return "".join(r)
413
413
414 def capabilities(repo, proto):
414 def capabilities(repo, proto):
415 caps = ('lookup changegroupsubset branchmap pushkey known getbundle '
415 caps = ('lookup changegroupsubset branchmap pushkey known getbundle '
416 'unbundlehash batch').split()
416 'unbundlehash batch').split()
417 if _allowstream(repo.ui):
417 if _allowstream(repo.ui):
418 if repo.ui.configbool('server', 'preferuncompressed', False):
418 if repo.ui.configbool('server', 'preferuncompressed', False):
419 caps.append('stream-preferred')
419 caps.append('stream-preferred')
420 requiredformats = repo.requirements & repo.supportedformats
420 requiredformats = repo.requirements & repo.supportedformats
421 # if our local revlogs are just revlogv1, add 'stream' cap
421 # if our local revlogs are just revlogv1, add 'stream' cap
422 if not requiredformats - set(('revlogv1',)):
422 if not requiredformats - set(('revlogv1',)):
423 caps.append('stream')
423 caps.append('stream')
424 # otherwise, add 'streamreqs' detailing our local revlog format
424 # otherwise, add 'streamreqs' detailing our local revlog format
425 else:
425 else:
426 caps.append('streamreqs=%s' % ','.join(requiredformats))
426 caps.append('streamreqs=%s' % ','.join(requiredformats))
427 caps.append('unbundle=%s' % ','.join(changegroupmod.bundlepriority))
427 caps.append('unbundle=%s' % ','.join(changegroupmod.bundlepriority))
428 caps.append('httpheader=1024')
428 caps.append('httpheader=1024')
429 return ' '.join(caps)
429 return ' '.join(caps)
430
430
431 def changegroup(repo, proto, roots):
431 def changegroup(repo, proto, roots):
432 nodes = decodelist(roots)
432 nodes = decodelist(roots)
433 cg = repo.changegroup(nodes, 'serve')
433 cg = repo.changegroup(nodes, 'serve')
434 return streamres(proto.groupchunks(cg))
434 return streamres(proto.groupchunks(cg))
435
435
436 def changegroupsubset(repo, proto, bases, heads):
436 def changegroupsubset(repo, proto, bases, heads):
437 bases = decodelist(bases)
437 bases = decodelist(bases)
438 heads = decodelist(heads)
438 heads = decodelist(heads)
439 cg = repo.changegroupsubset(bases, heads, 'serve')
439 cg = repo.changegroupsubset(bases, heads, 'serve')
440 return streamres(proto.groupchunks(cg))
440 return streamres(proto.groupchunks(cg))
441
441
442 def debugwireargs(repo, proto, one, two, others):
442 def debugwireargs(repo, proto, one, two, others):
443 # only accept optional args from the known set
443 # only accept optional args from the known set
444 opts = options('debugwireargs', ['three', 'four'], others)
444 opts = options('debugwireargs', ['three', 'four'], others)
445 return repo.debugwireargs(one, two, **opts)
445 return repo.debugwireargs(one, two, **opts)
446
446
447 def getbundle(repo, proto, others):
447 def getbundle(repo, proto, others):
448 opts = options('getbundle', ['heads', 'common'], others)
448 opts = options('getbundle', ['heads', 'common'], others)
449 for k, v in opts.iteritems():
449 for k, v in opts.iteritems():
450 opts[k] = decodelist(v)
450 opts[k] = decodelist(v)
451 cg = repo.getbundle('serve', **opts)
451 cg = repo.getbundle('serve', **opts)
452 return streamres(proto.groupchunks(cg))
452 return streamres(proto.groupchunks(cg))
453
453
454 def heads(repo, proto):
454 def heads(repo, proto):
455 h = phases.visibleheads(repo)
455 h = phases.visibleheads(repo)
456 return encodelist(h) + "\n"
456 return encodelist(h) + "\n"
457
457
458 def hello(repo, proto):
458 def hello(repo, proto):
459 '''the hello command returns a set of lines describing various
459 '''the hello command returns a set of lines describing various
460 interesting things about the server, in an RFC822-like format.
460 interesting things about the server, in an RFC822-like format.
461 Currently the only one defined is "capabilities", which
461 Currently the only one defined is "capabilities", which
462 consists of a line in the form:
462 consists of a line in the form:
463
463
464 capabilities: space separated list of tokens
464 capabilities: space separated list of tokens
465 '''
465 '''
466 return "capabilities: %s\n" % (capabilities(repo, proto))
466 return "capabilities: %s\n" % (capabilities(repo, proto))
467
467
468 def listkeys(repo, proto, namespace):
468 def listkeys(repo, proto, namespace):
469 d = repo.listkeys(encoding.tolocal(namespace)).items()
469 d = repo.listkeys(encoding.tolocal(namespace)).items()
470 t = '\n'.join(['%s\t%s' % (encoding.fromlocal(k), encoding.fromlocal(v))
470 t = '\n'.join(['%s\t%s' % (encoding.fromlocal(k), encoding.fromlocal(v))
471 for k, v in d])
471 for k, v in d])
472 return t
472 return t
473
473
474 def lookup(repo, proto, key):
474 def lookup(repo, proto, key):
475 try:
475 try:
476 k = encoding.tolocal(key)
476 k = encoding.tolocal(key)
477 c = repo[k]
477 c = repo[k]
478 if c.phase() == phases.secret:
478 if c.phase() == phases.secret:
479 raise error.RepoLookupError(_("unknown revision '%s'") % k)
479 raise error.RepoLookupError(_("unknown revision '%s'") % k)
480 r = c.hex()
480 r = c.hex()
481 success = 1
481 success = 1
482 except Exception, inst:
482 except Exception, inst:
483 r = str(inst)
483 r = str(inst)
484 success = 0
484 success = 0
485 return "%s %s\n" % (success, r)
485 return "%s %s\n" % (success, r)
486
486
487 def known(repo, proto, nodes, others):
487 def known(repo, proto, nodes, others):
488 return ''.join(b and "1" or "0" for b in repo.known(decodelist(nodes)))
488 return ''.join(b and "1" or "0" for b in repo.known(decodelist(nodes)))
489
489
490 def pushkey(repo, proto, namespace, key, old, new):
490 def pushkey(repo, proto, namespace, key, old, new):
491 # compatibility with pre-1.8 clients which were accidentally
491 # compatibility with pre-1.8 clients which were accidentally
492 # sending raw binary nodes rather than utf-8-encoded hex
492 # sending raw binary nodes rather than utf-8-encoded hex
493 if len(new) == 20 and new.encode('string-escape') != new:
493 if len(new) == 20 and new.encode('string-escape') != new:
494 # looks like it could be a binary node
494 # looks like it could be a binary node
495 try:
495 try:
496 new.decode('utf-8')
496 new.decode('utf-8')
497 new = encoding.tolocal(new) # but cleanly decodes as UTF-8
497 new = encoding.tolocal(new) # but cleanly decodes as UTF-8
498 except UnicodeDecodeError:
498 except UnicodeDecodeError:
499 pass # binary, leave unmodified
499 pass # binary, leave unmodified
500 else:
500 else:
501 new = encoding.tolocal(new) # normal path
501 new = encoding.tolocal(new) # normal path
502
502
503 r = repo.pushkey(encoding.tolocal(namespace), encoding.tolocal(key),
503 r = repo.pushkey(encoding.tolocal(namespace), encoding.tolocal(key),
504 encoding.tolocal(old), new)
504 encoding.tolocal(old), new)
505 return '%s\n' % int(r)
505 return '%s\n' % int(r)
506
506
507 def _allowstream(ui):
507 def _allowstream(ui):
508 return ui.configbool('server', 'uncompressed', True, untrusted=True)
508 return ui.configbool('server', 'uncompressed', True, untrusted=True)
509
509
510 def stream(repo, proto):
510 def stream(repo, proto):
511 '''If the server supports streaming clone, it advertises the "stream"
511 '''If the server supports streaming clone, it advertises the "stream"
512 capability with a value representing the version and flags of the repo
512 capability with a value representing the version and flags of the repo
513 it is serving. Client checks to see if it understands the format.
513 it is serving. Client checks to see if it understands the format.
514
514
515 The format is simple: the server writes out a line with the amount
515 The format is simple: the server writes out a line with the amount
516 of files, then the total amount of bytes to be transfered (separated
516 of files, then the total amount of bytes to be transfered (separated
517 by a space). Then, for each file, the server first writes the filename
517 by a space). Then, for each file, the server first writes the filename
518 and filesize (separated by the null character), then the file contents.
518 and filesize (separated by the null character), then the file contents.
519 '''
519 '''
520
520
521 if not _allowstream(repo.ui):
521 if not _allowstream(repo.ui):
522 return '1\n'
522 return '1\n'
523
523
524 entries = []
524 entries = []
525 total_bytes = 0
525 total_bytes = 0
526 try:
526 try:
527 # get consistent snapshot of repo, lock during scan
527 # get consistent snapshot of repo, lock during scan
528 lock = repo.lock()
528 lock = repo.lock()
529 try:
529 try:
530 repo.ui.debug('scanning\n')
530 repo.ui.debug('scanning\n')
531 for name, ename, size in repo.store.walk():
531 for name, ename, size in repo.store.walk():
532 entries.append((name, size))
532 entries.append((name, size))
533 total_bytes += size
533 total_bytes += size
534 finally:
534 finally:
535 lock.release()
535 lock.release()
536 except error.LockError:
536 except error.LockError:
537 return '2\n' # error: 2
537 return '2\n' # error: 2
538
538
539 def streamer(repo, entries, total):
539 def streamer(repo, entries, total):
540 '''stream out all metadata files in repository.'''
540 '''stream out all metadata files in repository.'''
541 yield '0\n' # success
541 yield '0\n' # success
542 repo.ui.debug('%d files, %d bytes to transfer\n' %
542 repo.ui.debug('%d files, %d bytes to transfer\n' %
543 (len(entries), total_bytes))
543 (len(entries), total_bytes))
544 yield '%d %d\n' % (len(entries), total_bytes)
544 yield '%d %d\n' % (len(entries), total_bytes)
545 for name, size in entries:
545 for name, size in entries:
546 repo.ui.debug('sending %s (%d bytes)\n' % (name, size))
546 repo.ui.debug('sending %s (%d bytes)\n' % (name, size))
547 # partially encode name over the wire for backwards compat
547 # partially encode name over the wire for backwards compat
548 yield '%s\0%d\n' % (store.encodedir(name), size)
548 yield '%s\0%d\n' % (store.encodedir(name), size)
549 for chunk in util.filechunkiter(repo.sopener(name), limit=size):
549 for chunk in util.filechunkiter(repo.sopener(name), limit=size):
550 yield chunk
550 yield chunk
551
551
552 return streamres(streamer(repo, entries, total_bytes))
552 return streamres(streamer(repo, entries, total_bytes))
553
553
554 def unbundle(repo, proto, heads):
554 def unbundle(repo, proto, heads):
555 their_heads = decodelist(heads)
555 their_heads = decodelist(heads)
556
556
557 def check_heads():
557 def check_heads():
558 heads = phases.visibleheads(repo)
558 heads = phases.visibleheads(repo)
559 heads_hash = util.sha1(''.join(sorted(heads))).digest()
559 heads_hash = util.sha1(''.join(sorted(heads))).digest()
560 return (their_heads == ['force'] or their_heads == heads or
560 return (their_heads == ['force'] or their_heads == heads or
561 their_heads == ['hashed', heads_hash])
561 their_heads == ['hashed', heads_hash])
562
562
563 proto.redirect()
563 proto.redirect()
564
564
565 # fail early if possible
565 # fail early if possible
566 if not check_heads():
566 if not check_heads():
567 return pusherr('unsynced changes')
567 return pusherr('unsynced changes')
568
568
569 # write bundle data to temporary file because it can be big
569 # write bundle data to temporary file because it can be big
570 fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
570 fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
571 fp = os.fdopen(fd, 'wb+')
571 fp = os.fdopen(fd, 'wb+')
572 r = 0
572 r = 0
573 try:
573 try:
574 proto.getfile(fp)
574 proto.getfile(fp)
575 lock = repo.lock()
575 lock = repo.lock()
576 try:
576 try:
577 if not check_heads():
577 if not check_heads():
578 # someone else committed/pushed/unbundled while we
578 # someone else committed/pushed/unbundled while we
579 # were transferring data
579 # were transferring data
580 return pusherr('unsynced changes')
580 return pusherr('unsynced changes')
581
581
582 # push can proceed
582 # push can proceed
583 fp.seek(0)
583 fp.seek(0)
584 gen = changegroupmod.readbundle(fp, None)
584 gen = changegroupmod.readbundle(fp, None)
585
585
586 try:
586 try:
587 r = repo.addchangegroup(gen, 'serve', proto._client())
587 r = repo.addchangegroup(gen, 'serve', proto._client())
588 except util.Abort, inst:
588 except util.Abort, inst:
589 sys.stderr.write("abort: %s\n" % inst)
589 sys.stderr.write("abort: %s\n" % inst)
590 finally:
590 finally:
591 lock.release()
591 lock.release()
592 return pushres(r)
592 return pushres(r)
593
593
594 finally:
594 finally:
595 fp.close()
595 fp.close()
596 os.unlink(tempname)
596 os.unlink(tempname)
597
597
598 commands = {
598 commands = {
599 'batch': (batch, 'cmds *'),
599 'batch': (batch, 'cmds *'),
600 'between': (between, 'pairs'),
600 'between': (between, 'pairs'),
601 'branchmap': (branchmap, ''),
601 'branchmap': (branchmap, ''),
602 'branches': (branches, 'nodes'),
602 'branches': (branches, 'nodes'),
603 'capabilities': (capabilities, ''),
603 'capabilities': (capabilities, ''),
604 'changegroup': (changegroup, 'roots'),
604 'changegroup': (changegroup, 'roots'),
605 'changegroupsubset': (changegroupsubset, 'bases heads'),
605 'changegroupsubset': (changegroupsubset, 'bases heads'),
606 'debugwireargs': (debugwireargs, 'one two *'),
606 'debugwireargs': (debugwireargs, 'one two *'),
607 'getbundle': (getbundle, '*'),
607 'getbundle': (getbundle, '*'),
608 'heads': (heads, ''),
608 'heads': (heads, ''),
609 'hello': (hello, ''),
609 'hello': (hello, ''),
610 'known': (known, 'nodes *'),
610 'known': (known, 'nodes *'),
611 'listkeys': (listkeys, 'namespace'),
611 'listkeys': (listkeys, 'namespace'),
612 'lookup': (lookup, 'key'),
612 'lookup': (lookup, 'key'),
613 'pushkey': (pushkey, 'namespace key old new'),
613 'pushkey': (pushkey, 'namespace key old new'),
614 'stream_out': (stream, ''),
614 'stream_out': (stream, ''),
615 'unbundle': (unbundle, 'heads'),
615 'unbundle': (unbundle, 'heads'),
616 }
616 }
@@ -1,1055 +1,1063 b''
1 $ cat >> $HGRCPATH <<EOF
1 $ cat >> $HGRCPATH <<EOF
2 > [extensions]
2 > [extensions]
3 > graphlog=
3 > graphlog=
4 > EOF
4 > EOF
5 $ hgph() { hg log -G --template "{rev} {phase} {desc} - {node|short}\n" $*; }
5 $ hgph() { hg log -G --template "{rev} {phase} {desc} - {node|short}\n" $*; }
6
6
7 $ mkcommit() {
7 $ mkcommit() {
8 > echo "$1" > "$1"
8 > echo "$1" > "$1"
9 > hg add "$1"
9 > hg add "$1"
10 > message="$1"
10 > message="$1"
11 > shift
11 > shift
12 > hg ci -m "$message" $*
12 > hg ci -m "$message" $*
13 > }
13 > }
14
14
15 $ hg init alpha
15 $ hg init alpha
16 $ cd alpha
16 $ cd alpha
17 $ mkcommit a-A
17 $ mkcommit a-A
18 $ mkcommit a-B
18 $ mkcommit a-B
19 $ mkcommit a-C
19 $ mkcommit a-C
20 $ mkcommit a-D
20 $ mkcommit a-D
21 $ hgph
21 $ hgph
22 @ 3 draft a-D - b555f63b6063
22 @ 3 draft a-D - b555f63b6063
23 |
23 |
24 o 2 draft a-C - 54acac6f23ab
24 o 2 draft a-C - 54acac6f23ab
25 |
25 |
26 o 1 draft a-B - 548a3d25dbf0
26 o 1 draft a-B - 548a3d25dbf0
27 |
27 |
28 o 0 draft a-A - 054250a37db4
28 o 0 draft a-A - 054250a37db4
29
29
30
30
31 $ hg init ../beta
31 $ hg init ../beta
32 $ hg push -r 1 ../beta
32 $ hg push -r 1 ../beta
33 pushing to ../beta
33 pushing to ../beta
34 searching for changes
34 searching for changes
35 adding changesets
35 adding changesets
36 adding manifests
36 adding manifests
37 adding file changes
37 adding file changes
38 added 2 changesets with 2 changes to 2 files
38 added 2 changesets with 2 changes to 2 files
39 $ hgph
39 $ hgph
40 @ 3 draft a-D - b555f63b6063
40 @ 3 draft a-D - b555f63b6063
41 |
41 |
42 o 2 draft a-C - 54acac6f23ab
42 o 2 draft a-C - 54acac6f23ab
43 |
43 |
44 o 1 public a-B - 548a3d25dbf0
44 o 1 public a-B - 548a3d25dbf0
45 |
45 |
46 o 0 public a-A - 054250a37db4
46 o 0 public a-A - 054250a37db4
47
47
48
48
49 $ cd ../beta
49 $ cd ../beta
50 $ hgph
50 $ hgph
51 o 1 public a-B - 548a3d25dbf0
51 o 1 public a-B - 548a3d25dbf0
52 |
52 |
53 o 0 public a-A - 054250a37db4
53 o 0 public a-A - 054250a37db4
54
54
55 $ hg up -q
55 $ hg up -q
56 $ mkcommit b-A
56 $ mkcommit b-A
57 $ hgph
57 $ hgph
58 @ 2 draft b-A - f54f1bb90ff3
58 @ 2 draft b-A - f54f1bb90ff3
59 |
59 |
60 o 1 public a-B - 548a3d25dbf0
60 o 1 public a-B - 548a3d25dbf0
61 |
61 |
62 o 0 public a-A - 054250a37db4
62 o 0 public a-A - 054250a37db4
63
63
64 $ hg pull ../alpha
64 $ hg pull ../alpha
65 pulling from ../alpha
65 pulling from ../alpha
66 searching for changes
66 searching for changes
67 adding changesets
67 adding changesets
68 adding manifests
68 adding manifests
69 adding file changes
69 adding file changes
70 added 2 changesets with 2 changes to 2 files (+1 heads)
70 added 2 changesets with 2 changes to 2 files (+1 heads)
71 (run 'hg heads' to see heads, 'hg merge' to merge)
71 (run 'hg heads' to see heads, 'hg merge' to merge)
72 $ hgph
72 $ hgph
73 o 4 public a-D - b555f63b6063
73 o 4 public a-D - b555f63b6063
74 |
74 |
75 o 3 public a-C - 54acac6f23ab
75 o 3 public a-C - 54acac6f23ab
76 |
76 |
77 | @ 2 draft b-A - f54f1bb90ff3
77 | @ 2 draft b-A - f54f1bb90ff3
78 |/
78 |/
79 o 1 public a-B - 548a3d25dbf0
79 o 1 public a-B - 548a3d25dbf0
80 |
80 |
81 o 0 public a-A - 054250a37db4
81 o 0 public a-A - 054250a37db4
82
82
83
83
84 pull did not updated ../alpha state.
84 pull did not updated ../alpha state.
85 push from alpha to beta should update phase even if nothing is transfered
85 push from alpha to beta should update phase even if nothing is transfered
86
86
87 $ cd ../alpha
87 $ cd ../alpha
88 $ hgph # not updated by remote pull
88 $ hgph # not updated by remote pull
89 @ 3 draft a-D - b555f63b6063
89 @ 3 draft a-D - b555f63b6063
90 |
90 |
91 o 2 draft a-C - 54acac6f23ab
91 o 2 draft a-C - 54acac6f23ab
92 |
92 |
93 o 1 public a-B - 548a3d25dbf0
93 o 1 public a-B - 548a3d25dbf0
94 |
94 |
95 o 0 public a-A - 054250a37db4
95 o 0 public a-A - 054250a37db4
96
96
97 $ hg push ../beta
97 $ hg push ../beta
98 pushing to ../beta
98 pushing to ../beta
99 searching for changes
99 searching for changes
100 no changes found
100 no changes found
101 [1]
101 [1]
102 $ hgph
102 $ hgph
103 @ 3 public a-D - b555f63b6063
103 @ 3 public a-D - b555f63b6063
104 |
104 |
105 o 2 public a-C - 54acac6f23ab
105 o 2 public a-C - 54acac6f23ab
106 |
106 |
107 o 1 public a-B - 548a3d25dbf0
107 o 1 public a-B - 548a3d25dbf0
108 |
108 |
109 o 0 public a-A - 054250a37db4
109 o 0 public a-A - 054250a37db4
110
110
111
111
112 update must update phase of common changeset too
112 update must update phase of common changeset too
113
113
114 $ hg pull ../beta # getting b-A
114 $ hg pull ../beta # getting b-A
115 pulling from ../beta
115 pulling from ../beta
116 searching for changes
116 searching for changes
117 adding changesets
117 adding changesets
118 adding manifests
118 adding manifests
119 adding file changes
119 adding file changes
120 added 1 changesets with 1 changes to 1 files (+1 heads)
120 added 1 changesets with 1 changes to 1 files (+1 heads)
121 (run 'hg heads' to see heads, 'hg merge' to merge)
121 (run 'hg heads' to see heads, 'hg merge' to merge)
122
122
123 $ cd ../beta
123 $ cd ../beta
124 $ hgph # not updated by remote pull
124 $ hgph # not updated by remote pull
125 o 4 public a-D - b555f63b6063
125 o 4 public a-D - b555f63b6063
126 |
126 |
127 o 3 public a-C - 54acac6f23ab
127 o 3 public a-C - 54acac6f23ab
128 |
128 |
129 | @ 2 draft b-A - f54f1bb90ff3
129 | @ 2 draft b-A - f54f1bb90ff3
130 |/
130 |/
131 o 1 public a-B - 548a3d25dbf0
131 o 1 public a-B - 548a3d25dbf0
132 |
132 |
133 o 0 public a-A - 054250a37db4
133 o 0 public a-A - 054250a37db4
134
134
135 $ hg pull ../alpha
135 $ hg pull ../alpha
136 pulling from ../alpha
136 pulling from ../alpha
137 searching for changes
137 searching for changes
138 no changes found
138 no changes found
139 $ hgph
139 $ hgph
140 o 4 public a-D - b555f63b6063
140 o 4 public a-D - b555f63b6063
141 |
141 |
142 o 3 public a-C - 54acac6f23ab
142 o 3 public a-C - 54acac6f23ab
143 |
143 |
144 | @ 2 public b-A - f54f1bb90ff3
144 | @ 2 public b-A - f54f1bb90ff3
145 |/
145 |/
146 o 1 public a-B - 548a3d25dbf0
146 o 1 public a-B - 548a3d25dbf0
147 |
147 |
148 o 0 public a-A - 054250a37db4
148 o 0 public a-A - 054250a37db4
149
149
150
150
151 Publish configuration option
151 Publish configuration option
152 ----------------------------
152 ----------------------------
153
153
154 Pull
154 Pull
155 ````
155 ````
156
156
157 changegroup are added without phase movement
157 changegroup are added without phase movement
158
158
159 $ hg bundle -a ../base.bundle
159 $ hg bundle -a ../base.bundle
160 5 changesets found
160 5 changesets found
161 $ cd ..
161 $ cd ..
162 $ hg init mu
162 $ hg init mu
163 $ cd mu
163 $ cd mu
164 $ cat > .hg/hgrc << EOF
164 $ cat > .hg/hgrc << EOF
165 > [phases]
165 > [phases]
166 > publish=0
166 > publish=0
167 > EOF
167 > EOF
168 $ hg unbundle ../base.bundle
168 $ hg unbundle ../base.bundle
169 adding changesets
169 adding changesets
170 adding manifests
170 adding manifests
171 adding file changes
171 adding file changes
172 added 5 changesets with 5 changes to 5 files (+1 heads)
172 added 5 changesets with 5 changes to 5 files (+1 heads)
173 (run 'hg heads' to see heads, 'hg merge' to merge)
173 (run 'hg heads' to see heads, 'hg merge' to merge)
174 $ hgph
174 $ hgph
175 o 4 draft a-D - b555f63b6063
175 o 4 draft a-D - b555f63b6063
176 |
176 |
177 o 3 draft a-C - 54acac6f23ab
177 o 3 draft a-C - 54acac6f23ab
178 |
178 |
179 | o 2 draft b-A - f54f1bb90ff3
179 | o 2 draft b-A - f54f1bb90ff3
180 |/
180 |/
181 o 1 draft a-B - 548a3d25dbf0
181 o 1 draft a-B - 548a3d25dbf0
182 |
182 |
183 o 0 draft a-A - 054250a37db4
183 o 0 draft a-A - 054250a37db4
184
184
185 $ cd ..
185 $ cd ..
186
186
187 Pulling from publish=False to publish=False does not move boundary.
187 Pulling from publish=False to publish=False does not move boundary.
188
188
189 $ hg init nu
189 $ hg init nu
190 $ cd nu
190 $ cd nu
191 $ cat > .hg/hgrc << EOF
191 $ cat > .hg/hgrc << EOF
192 > [phases]
192 > [phases]
193 > publish=0
193 > publish=0
194 > EOF
194 > EOF
195 $ hg pull ../mu -r 54acac6f23ab
195 $ hg pull ../mu -r 54acac6f23ab
196 pulling from ../mu
196 pulling from ../mu
197 adding changesets
197 adding changesets
198 adding manifests
198 adding manifests
199 adding file changes
199 adding file changes
200 added 3 changesets with 3 changes to 3 files
200 added 3 changesets with 3 changes to 3 files
201 (run 'hg update' to get a working copy)
201 (run 'hg update' to get a working copy)
202 $ hgph
202 $ hgph
203 o 2 draft a-C - 54acac6f23ab
203 o 2 draft a-C - 54acac6f23ab
204 |
204 |
205 o 1 draft a-B - 548a3d25dbf0
205 o 1 draft a-B - 548a3d25dbf0
206 |
206 |
207 o 0 draft a-A - 054250a37db4
207 o 0 draft a-A - 054250a37db4
208
208
209
209
210 Even for common
210 Even for common
211
211
212 $ hg pull ../mu -r f54f1bb90ff3
212 $ hg pull ../mu -r f54f1bb90ff3
213 pulling from ../mu
213 pulling from ../mu
214 searching for changes
214 searching for changes
215 adding changesets
215 adding changesets
216 adding manifests
216 adding manifests
217 adding file changes
217 adding file changes
218 added 1 changesets with 1 changes to 1 files (+1 heads)
218 added 1 changesets with 1 changes to 1 files (+1 heads)
219 (run 'hg heads' to see heads, 'hg merge' to merge)
219 (run 'hg heads' to see heads, 'hg merge' to merge)
220 $ hgph
220 $ hgph
221 o 3 draft b-A - f54f1bb90ff3
221 o 3 draft b-A - f54f1bb90ff3
222 |
222 |
223 | o 2 draft a-C - 54acac6f23ab
223 | o 2 draft a-C - 54acac6f23ab
224 |/
224 |/
225 o 1 draft a-B - 548a3d25dbf0
225 o 1 draft a-B - 548a3d25dbf0
226 |
226 |
227 o 0 draft a-A - 054250a37db4
227 o 0 draft a-A - 054250a37db4
228
228
229
229
230
230
231 Pulling from Publish=True to Publish=False move boundary in common set.
231 Pulling from Publish=True to Publish=False move boundary in common set.
232 we are in nu
232 we are in nu
233
233
234 $ hg pull ../alpha -r b555f63b6063
234 $ hg pull ../alpha -r b555f63b6063
235 pulling from ../alpha
235 pulling from ../alpha
236 searching for changes
236 searching for changes
237 adding changesets
237 adding changesets
238 adding manifests
238 adding manifests
239 adding file changes
239 adding file changes
240 added 1 changesets with 1 changes to 1 files
240 added 1 changesets with 1 changes to 1 files
241 (run 'hg update' to get a working copy)
241 (run 'hg update' to get a working copy)
242 $ hgph # f54f1bb90ff3 stay draft, not ancestor of -r
242 $ hgph # f54f1bb90ff3 stay draft, not ancestor of -r
243 o 4 public a-D - b555f63b6063
243 o 4 public a-D - b555f63b6063
244 |
244 |
245 | o 3 draft b-A - f54f1bb90ff3
245 | o 3 draft b-A - f54f1bb90ff3
246 | |
246 | |
247 o | 2 public a-C - 54acac6f23ab
247 o | 2 public a-C - 54acac6f23ab
248 |/
248 |/
249 o 1 public a-B - 548a3d25dbf0
249 o 1 public a-B - 548a3d25dbf0
250 |
250 |
251 o 0 public a-A - 054250a37db4
251 o 0 public a-A - 054250a37db4
252
252
253
253
254 pulling from Publish=False to publish=False with some public
254 pulling from Publish=False to publish=False with some public
255
255
256 $ hg up -q f54f1bb90ff3
256 $ hg up -q f54f1bb90ff3
257 $ mkcommit n-A
257 $ mkcommit n-A
258 $ mkcommit n-B
258 $ mkcommit n-B
259 $ hgph
259 $ hgph
260 @ 6 draft n-B - 145e75495359
260 @ 6 draft n-B - 145e75495359
261 |
261 |
262 o 5 draft n-A - d6bcb4f74035
262 o 5 draft n-A - d6bcb4f74035
263 |
263 |
264 | o 4 public a-D - b555f63b6063
264 | o 4 public a-D - b555f63b6063
265 | |
265 | |
266 o | 3 draft b-A - f54f1bb90ff3
266 o | 3 draft b-A - f54f1bb90ff3
267 | |
267 | |
268 | o 2 public a-C - 54acac6f23ab
268 | o 2 public a-C - 54acac6f23ab
269 |/
269 |/
270 o 1 public a-B - 548a3d25dbf0
270 o 1 public a-B - 548a3d25dbf0
271 |
271 |
272 o 0 public a-A - 054250a37db4
272 o 0 public a-A - 054250a37db4
273
273
274 $ cd ../mu
274 $ cd ../mu
275 $ hg pull ../nu
275 $ hg pull ../nu
276 pulling from ../nu
276 pulling from ../nu
277 searching for changes
277 searching for changes
278 adding changesets
278 adding changesets
279 adding manifests
279 adding manifests
280 adding file changes
280 adding file changes
281 added 2 changesets with 2 changes to 2 files
281 added 2 changesets with 2 changes to 2 files
282 (run 'hg update' to get a working copy)
282 (run 'hg update' to get a working copy)
283 $ hgph
283 $ hgph
284 o 6 draft n-B - 145e75495359
284 o 6 draft n-B - 145e75495359
285 |
285 |
286 o 5 draft n-A - d6bcb4f74035
286 o 5 draft n-A - d6bcb4f74035
287 |
287 |
288 | o 4 public a-D - b555f63b6063
288 | o 4 public a-D - b555f63b6063
289 | |
289 | |
290 | o 3 public a-C - 54acac6f23ab
290 | o 3 public a-C - 54acac6f23ab
291 | |
291 | |
292 o | 2 draft b-A - f54f1bb90ff3
292 o | 2 draft b-A - f54f1bb90ff3
293 |/
293 |/
294 o 1 public a-B - 548a3d25dbf0
294 o 1 public a-B - 548a3d25dbf0
295 |
295 |
296 o 0 public a-A - 054250a37db4
296 o 0 public a-A - 054250a37db4
297
297
298 $ cd ..
298 $ cd ..
299
299
300 pulling into publish=True
300 pulling into publish=True
301
301
302 $ cd alpha
302 $ cd alpha
303 $ hgph
303 $ hgph
304 o 4 public b-A - f54f1bb90ff3
304 o 4 public b-A - f54f1bb90ff3
305 |
305 |
306 | @ 3 public a-D - b555f63b6063
306 | @ 3 public a-D - b555f63b6063
307 | |
307 | |
308 | o 2 public a-C - 54acac6f23ab
308 | o 2 public a-C - 54acac6f23ab
309 |/
309 |/
310 o 1 public a-B - 548a3d25dbf0
310 o 1 public a-B - 548a3d25dbf0
311 |
311 |
312 o 0 public a-A - 054250a37db4
312 o 0 public a-A - 054250a37db4
313
313
314 $ hg pull ../mu
314 $ hg pull ../mu
315 pulling from ../mu
315 pulling from ../mu
316 searching for changes
316 searching for changes
317 adding changesets
317 adding changesets
318 adding manifests
318 adding manifests
319 adding file changes
319 adding file changes
320 added 2 changesets with 2 changes to 2 files
320 added 2 changesets with 2 changes to 2 files
321 (run 'hg update' to get a working copy)
321 (run 'hg update' to get a working copy)
322 $ hgph
322 $ hgph
323 o 6 draft n-B - 145e75495359
323 o 6 draft n-B - 145e75495359
324 |
324 |
325 o 5 draft n-A - d6bcb4f74035
325 o 5 draft n-A - d6bcb4f74035
326 |
326 |
327 o 4 public b-A - f54f1bb90ff3
327 o 4 public b-A - f54f1bb90ff3
328 |
328 |
329 | @ 3 public a-D - b555f63b6063
329 | @ 3 public a-D - b555f63b6063
330 | |
330 | |
331 | o 2 public a-C - 54acac6f23ab
331 | o 2 public a-C - 54acac6f23ab
332 |/
332 |/
333 o 1 public a-B - 548a3d25dbf0
333 o 1 public a-B - 548a3d25dbf0
334 |
334 |
335 o 0 public a-A - 054250a37db4
335 o 0 public a-A - 054250a37db4
336
336
337 $ cd ..
337 $ cd ..
338
338
339 pulling back into original repo
339 pulling back into original repo
340
340
341 $ cd nu
341 $ cd nu
342 $ hg pull ../alpha
342 $ hg pull ../alpha
343 pulling from ../alpha
343 pulling from ../alpha
344 searching for changes
344 searching for changes
345 no changes found
345 no changes found
346 $ hgph
346 $ hgph
347 @ 6 public n-B - 145e75495359
347 @ 6 public n-B - 145e75495359
348 |
348 |
349 o 5 public n-A - d6bcb4f74035
349 o 5 public n-A - d6bcb4f74035
350 |
350 |
351 | o 4 public a-D - b555f63b6063
351 | o 4 public a-D - b555f63b6063
352 | |
352 | |
353 o | 3 public b-A - f54f1bb90ff3
353 o | 3 public b-A - f54f1bb90ff3
354 | |
354 | |
355 | o 2 public a-C - 54acac6f23ab
355 | o 2 public a-C - 54acac6f23ab
356 |/
356 |/
357 o 1 public a-B - 548a3d25dbf0
357 o 1 public a-B - 548a3d25dbf0
358 |
358 |
359 o 0 public a-A - 054250a37db4
359 o 0 public a-A - 054250a37db4
360
360
361
361
362 Push
362 Push
363 ````
363 ````
364
364
365 (inserted)
365 (inserted)
366
366
367 Test that phase are pushed even when they are nothing to pus
367 Test that phase are pushed even when they are nothing to pus
368 (this might be tested later bu are very convenient to not alter too much test)
368 (this might be tested later bu are very convenient to not alter too much test)
369
369
370 Push back to alpha
370 Push back to alpha
371
371
372 $ hg push ../alpha # from nu
372 $ hg push ../alpha # from nu
373 pushing to ../alpha
373 pushing to ../alpha
374 searching for changes
374 searching for changes
375 no changes found
375 no changes found
376 [1]
376 [1]
377 $ cd ..
377 $ cd ..
378 $ cd alpha
378 $ cd alpha
379 $ hgph
379 $ hgph
380 o 6 public n-B - 145e75495359
380 o 6 public n-B - 145e75495359
381 |
381 |
382 o 5 public n-A - d6bcb4f74035
382 o 5 public n-A - d6bcb4f74035
383 |
383 |
384 o 4 public b-A - f54f1bb90ff3
384 o 4 public b-A - f54f1bb90ff3
385 |
385 |
386 | @ 3 public a-D - b555f63b6063
386 | @ 3 public a-D - b555f63b6063
387 | |
387 | |
388 | o 2 public a-C - 54acac6f23ab
388 | o 2 public a-C - 54acac6f23ab
389 |/
389 |/
390 o 1 public a-B - 548a3d25dbf0
390 o 1 public a-B - 548a3d25dbf0
391 |
391 |
392 o 0 public a-A - 054250a37db4
392 o 0 public a-A - 054250a37db4
393
393
394
394
395 (end insertion)
395 (end insertion)
396
396
397
397
398 initial setup
398 initial setup
399
399
400 $ hg glog # of alpha
400 $ hg glog # of alpha
401 o changeset: 6:145e75495359
401 o changeset: 6:145e75495359
402 | tag: tip
402 | tag: tip
403 | user: test
403 | user: test
404 | date: Thu Jan 01 00:00:00 1970 +0000
404 | date: Thu Jan 01 00:00:00 1970 +0000
405 | summary: n-B
405 | summary: n-B
406 |
406 |
407 o changeset: 5:d6bcb4f74035
407 o changeset: 5:d6bcb4f74035
408 | user: test
408 | user: test
409 | date: Thu Jan 01 00:00:00 1970 +0000
409 | date: Thu Jan 01 00:00:00 1970 +0000
410 | summary: n-A
410 | summary: n-A
411 |
411 |
412 o changeset: 4:f54f1bb90ff3
412 o changeset: 4:f54f1bb90ff3
413 | parent: 1:548a3d25dbf0
413 | parent: 1:548a3d25dbf0
414 | user: test
414 | user: test
415 | date: Thu Jan 01 00:00:00 1970 +0000
415 | date: Thu Jan 01 00:00:00 1970 +0000
416 | summary: b-A
416 | summary: b-A
417 |
417 |
418 | @ changeset: 3:b555f63b6063
418 | @ changeset: 3:b555f63b6063
419 | | user: test
419 | | user: test
420 | | date: Thu Jan 01 00:00:00 1970 +0000
420 | | date: Thu Jan 01 00:00:00 1970 +0000
421 | | summary: a-D
421 | | summary: a-D
422 | |
422 | |
423 | o changeset: 2:54acac6f23ab
423 | o changeset: 2:54acac6f23ab
424 |/ user: test
424 |/ user: test
425 | date: Thu Jan 01 00:00:00 1970 +0000
425 | date: Thu Jan 01 00:00:00 1970 +0000
426 | summary: a-C
426 | summary: a-C
427 |
427 |
428 o changeset: 1:548a3d25dbf0
428 o changeset: 1:548a3d25dbf0
429 | user: test
429 | user: test
430 | date: Thu Jan 01 00:00:00 1970 +0000
430 | date: Thu Jan 01 00:00:00 1970 +0000
431 | summary: a-B
431 | summary: a-B
432 |
432 |
433 o changeset: 0:054250a37db4
433 o changeset: 0:054250a37db4
434 user: test
434 user: test
435 date: Thu Jan 01 00:00:00 1970 +0000
435 date: Thu Jan 01 00:00:00 1970 +0000
436 summary: a-A
436 summary: a-A
437
437
438 $ mkcommit a-E
438 $ mkcommit a-E
439 $ mkcommit a-F
439 $ mkcommit a-F
440 $ mkcommit a-G
440 $ mkcommit a-G
441 $ hg up d6bcb4f74035 -q
441 $ hg up d6bcb4f74035 -q
442 $ mkcommit a-H
442 $ mkcommit a-H
443 created new head
443 created new head
444 $ hgph
444 $ hgph
445 @ 10 draft a-H - 967b449fbc94
445 @ 10 draft a-H - 967b449fbc94
446 |
446 |
447 | o 9 draft a-G - 3e27b6f1eee1
447 | o 9 draft a-G - 3e27b6f1eee1
448 | |
448 | |
449 | o 8 draft a-F - b740e3e5c05d
449 | o 8 draft a-F - b740e3e5c05d
450 | |
450 | |
451 | o 7 draft a-E - e9f537e46dea
451 | o 7 draft a-E - e9f537e46dea
452 | |
452 | |
453 +---o 6 public n-B - 145e75495359
453 +---o 6 public n-B - 145e75495359
454 | |
454 | |
455 o | 5 public n-A - d6bcb4f74035
455 o | 5 public n-A - d6bcb4f74035
456 | |
456 | |
457 o | 4 public b-A - f54f1bb90ff3
457 o | 4 public b-A - f54f1bb90ff3
458 | |
458 | |
459 | o 3 public a-D - b555f63b6063
459 | o 3 public a-D - b555f63b6063
460 | |
460 | |
461 | o 2 public a-C - 54acac6f23ab
461 | o 2 public a-C - 54acac6f23ab
462 |/
462 |/
463 o 1 public a-B - 548a3d25dbf0
463 o 1 public a-B - 548a3d25dbf0
464 |
464 |
465 o 0 public a-A - 054250a37db4
465 o 0 public a-A - 054250a37db4
466
466
467
467
468 Pulling from bundle does not alter phases of changeset not present in the bundle
468 Pulling from bundle does not alter phases of changeset not present in the bundle
469
469
470 $ hg bundle --base 1 -r 6 -r 3 ../partial-bundle.hg
470 $ hg bundle --base 1 -r 6 -r 3 ../partial-bundle.hg
471 5 changesets found
471 5 changesets found
472 $ hg pull ../partial-bundle.hg
472 $ hg pull ../partial-bundle.hg
473 pulling from ../partial-bundle.hg
473 pulling from ../partial-bundle.hg
474 searching for changes
474 searching for changes
475 no changes found
475 no changes found
476 $ hgph
476 $ hgph
477 @ 10 draft a-H - 967b449fbc94
477 @ 10 draft a-H - 967b449fbc94
478 |
478 |
479 | o 9 draft a-G - 3e27b6f1eee1
479 | o 9 draft a-G - 3e27b6f1eee1
480 | |
480 | |
481 | o 8 draft a-F - b740e3e5c05d
481 | o 8 draft a-F - b740e3e5c05d
482 | |
482 | |
483 | o 7 draft a-E - e9f537e46dea
483 | o 7 draft a-E - e9f537e46dea
484 | |
484 | |
485 +---o 6 public n-B - 145e75495359
485 +---o 6 public n-B - 145e75495359
486 | |
486 | |
487 o | 5 public n-A - d6bcb4f74035
487 o | 5 public n-A - d6bcb4f74035
488 | |
488 | |
489 o | 4 public b-A - f54f1bb90ff3
489 o | 4 public b-A - f54f1bb90ff3
490 | |
490 | |
491 | o 3 public a-D - b555f63b6063
491 | o 3 public a-D - b555f63b6063
492 | |
492 | |
493 | o 2 public a-C - 54acac6f23ab
493 | o 2 public a-C - 54acac6f23ab
494 |/
494 |/
495 o 1 public a-B - 548a3d25dbf0
495 o 1 public a-B - 548a3d25dbf0
496 |
496 |
497 o 0 public a-A - 054250a37db4
497 o 0 public a-A - 054250a37db4
498
498
499
499
500 Pushing to Publish=False (unknown changeset)
500 Pushing to Publish=False (unknown changeset)
501
501
502 $ hg push ../mu -r b740e3e5c05d # a-F
502 $ hg push ../mu -r b740e3e5c05d # a-F
503 pushing to ../mu
503 pushing to ../mu
504 searching for changes
504 searching for changes
505 adding changesets
505 adding changesets
506 adding manifests
506 adding manifests
507 adding file changes
507 adding file changes
508 added 2 changesets with 2 changes to 2 files
508 added 2 changesets with 2 changes to 2 files
509 $ hgph
509 $ hgph
510 @ 10 draft a-H - 967b449fbc94
510 @ 10 draft a-H - 967b449fbc94
511 |
511 |
512 | o 9 draft a-G - 3e27b6f1eee1
512 | o 9 draft a-G - 3e27b6f1eee1
513 | |
513 | |
514 | o 8 draft a-F - b740e3e5c05d
514 | o 8 draft a-F - b740e3e5c05d
515 | |
515 | |
516 | o 7 draft a-E - e9f537e46dea
516 | o 7 draft a-E - e9f537e46dea
517 | |
517 | |
518 +---o 6 public n-B - 145e75495359
518 +---o 6 public n-B - 145e75495359
519 | |
519 | |
520 o | 5 public n-A - d6bcb4f74035
520 o | 5 public n-A - d6bcb4f74035
521 | |
521 | |
522 o | 4 public b-A - f54f1bb90ff3
522 o | 4 public b-A - f54f1bb90ff3
523 | |
523 | |
524 | o 3 public a-D - b555f63b6063
524 | o 3 public a-D - b555f63b6063
525 | |
525 | |
526 | o 2 public a-C - 54acac6f23ab
526 | o 2 public a-C - 54acac6f23ab
527 |/
527 |/
528 o 1 public a-B - 548a3d25dbf0
528 o 1 public a-B - 548a3d25dbf0
529 |
529 |
530 o 0 public a-A - 054250a37db4
530 o 0 public a-A - 054250a37db4
531
531
532
532
533 $ cd ../mu
533 $ cd ../mu
534 $ hgph # again f54f1bb90ff3, d6bcb4f74035 and 145e75495359 stay draft,
534 $ hgph # again f54f1bb90ff3, d6bcb4f74035 and 145e75495359 stay draft,
535 > # not ancestor of -r
535 > # not ancestor of -r
536 o 8 draft a-F - b740e3e5c05d
536 o 8 draft a-F - b740e3e5c05d
537 |
537 |
538 o 7 draft a-E - e9f537e46dea
538 o 7 draft a-E - e9f537e46dea
539 |
539 |
540 | o 6 draft n-B - 145e75495359
540 | o 6 draft n-B - 145e75495359
541 | |
541 | |
542 | o 5 draft n-A - d6bcb4f74035
542 | o 5 draft n-A - d6bcb4f74035
543 | |
543 | |
544 o | 4 public a-D - b555f63b6063
544 o | 4 public a-D - b555f63b6063
545 | |
545 | |
546 o | 3 public a-C - 54acac6f23ab
546 o | 3 public a-C - 54acac6f23ab
547 | |
547 | |
548 | o 2 draft b-A - f54f1bb90ff3
548 | o 2 draft b-A - f54f1bb90ff3
549 |/
549 |/
550 o 1 public a-B - 548a3d25dbf0
550 o 1 public a-B - 548a3d25dbf0
551 |
551 |
552 o 0 public a-A - 054250a37db4
552 o 0 public a-A - 054250a37db4
553
553
554
554
555 Pushing to Publish=True (unknown changeset)
555 Pushing to Publish=True (unknown changeset)
556
556
557 $ hg push ../beta -r b740e3e5c05d
557 $ hg push ../beta -r b740e3e5c05d
558 pushing to ../beta
558 pushing to ../beta
559 searching for changes
559 searching for changes
560 adding changesets
560 adding changesets
561 adding manifests
561 adding manifests
562 adding file changes
562 adding file changes
563 added 2 changesets with 2 changes to 2 files
563 added 2 changesets with 2 changes to 2 files
564 $ hgph # again f54f1bb90ff3, d6bcb4f74035 and 145e75495359 stay draft,
564 $ hgph # again f54f1bb90ff3, d6bcb4f74035 and 145e75495359 stay draft,
565 > # not ancestor of -r
565 > # not ancestor of -r
566 o 8 public a-F - b740e3e5c05d
566 o 8 public a-F - b740e3e5c05d
567 |
567 |
568 o 7 public a-E - e9f537e46dea
568 o 7 public a-E - e9f537e46dea
569 |
569 |
570 | o 6 draft n-B - 145e75495359
570 | o 6 draft n-B - 145e75495359
571 | |
571 | |
572 | o 5 draft n-A - d6bcb4f74035
572 | o 5 draft n-A - d6bcb4f74035
573 | |
573 | |
574 o | 4 public a-D - b555f63b6063
574 o | 4 public a-D - b555f63b6063
575 | |
575 | |
576 o | 3 public a-C - 54acac6f23ab
576 o | 3 public a-C - 54acac6f23ab
577 | |
577 | |
578 | o 2 draft b-A - f54f1bb90ff3
578 | o 2 draft b-A - f54f1bb90ff3
579 |/
579 |/
580 o 1 public a-B - 548a3d25dbf0
580 o 1 public a-B - 548a3d25dbf0
581 |
581 |
582 o 0 public a-A - 054250a37db4
582 o 0 public a-A - 054250a37db4
583
583
584
584
585 Pushing to Publish=True (common changeset)
585 Pushing to Publish=True (common changeset)
586
586
587 $ cd ../beta
587 $ cd ../beta
588 $ hg push ../alpha
588 $ hg push ../alpha
589 pushing to ../alpha
589 pushing to ../alpha
590 searching for changes
590 searching for changes
591 no changes found
591 no changes found
592 [1]
592 [1]
593 $ hgph
593 $ hgph
594 o 6 public a-F - b740e3e5c05d
594 o 6 public a-F - b740e3e5c05d
595 |
595 |
596 o 5 public a-E - e9f537e46dea
596 o 5 public a-E - e9f537e46dea
597 |
597 |
598 o 4 public a-D - b555f63b6063
598 o 4 public a-D - b555f63b6063
599 |
599 |
600 o 3 public a-C - 54acac6f23ab
600 o 3 public a-C - 54acac6f23ab
601 |
601 |
602 | @ 2 public b-A - f54f1bb90ff3
602 | @ 2 public b-A - f54f1bb90ff3
603 |/
603 |/
604 o 1 public a-B - 548a3d25dbf0
604 o 1 public a-B - 548a3d25dbf0
605 |
605 |
606 o 0 public a-A - 054250a37db4
606 o 0 public a-A - 054250a37db4
607
607
608 $ cd ../alpha
608 $ cd ../alpha
609 $ hgph
609 $ hgph
610 @ 10 draft a-H - 967b449fbc94
610 @ 10 draft a-H - 967b449fbc94
611 |
611 |
612 | o 9 draft a-G - 3e27b6f1eee1
612 | o 9 draft a-G - 3e27b6f1eee1
613 | |
613 | |
614 | o 8 public a-F - b740e3e5c05d
614 | o 8 public a-F - b740e3e5c05d
615 | |
615 | |
616 | o 7 public a-E - e9f537e46dea
616 | o 7 public a-E - e9f537e46dea
617 | |
617 | |
618 +---o 6 public n-B - 145e75495359
618 +---o 6 public n-B - 145e75495359
619 | |
619 | |
620 o | 5 public n-A - d6bcb4f74035
620 o | 5 public n-A - d6bcb4f74035
621 | |
621 | |
622 o | 4 public b-A - f54f1bb90ff3
622 o | 4 public b-A - f54f1bb90ff3
623 | |
623 | |
624 | o 3 public a-D - b555f63b6063
624 | o 3 public a-D - b555f63b6063
625 | |
625 | |
626 | o 2 public a-C - 54acac6f23ab
626 | o 2 public a-C - 54acac6f23ab
627 |/
627 |/
628 o 1 public a-B - 548a3d25dbf0
628 o 1 public a-B - 548a3d25dbf0
629 |
629 |
630 o 0 public a-A - 054250a37db4
630 o 0 public a-A - 054250a37db4
631
631
632
632
633 Pushing to Publish=False (common changeset that change phase + unknown one)
633 Pushing to Publish=False (common changeset that change phase + unknown one)
634
634
635 $ hg push ../mu -r 967b449fbc94 -f
635 $ hg push ../mu -r 967b449fbc94 -f
636 pushing to ../mu
636 pushing to ../mu
637 searching for changes
637 searching for changes
638 adding changesets
638 adding changesets
639 adding manifests
639 adding manifests
640 adding file changes
640 adding file changes
641 added 1 changesets with 1 changes to 1 files (+1 heads)
641 added 1 changesets with 1 changes to 1 files (+1 heads)
642 $ hgph
642 $ hgph
643 @ 10 draft a-H - 967b449fbc94
643 @ 10 draft a-H - 967b449fbc94
644 |
644 |
645 | o 9 draft a-G - 3e27b6f1eee1
645 | o 9 draft a-G - 3e27b6f1eee1
646 | |
646 | |
647 | o 8 public a-F - b740e3e5c05d
647 | o 8 public a-F - b740e3e5c05d
648 | |
648 | |
649 | o 7 public a-E - e9f537e46dea
649 | o 7 public a-E - e9f537e46dea
650 | |
650 | |
651 +---o 6 public n-B - 145e75495359
651 +---o 6 public n-B - 145e75495359
652 | |
652 | |
653 o | 5 public n-A - d6bcb4f74035
653 o | 5 public n-A - d6bcb4f74035
654 | |
654 | |
655 o | 4 public b-A - f54f1bb90ff3
655 o | 4 public b-A - f54f1bb90ff3
656 | |
656 | |
657 | o 3 public a-D - b555f63b6063
657 | o 3 public a-D - b555f63b6063
658 | |
658 | |
659 | o 2 public a-C - 54acac6f23ab
659 | o 2 public a-C - 54acac6f23ab
660 |/
660 |/
661 o 1 public a-B - 548a3d25dbf0
661 o 1 public a-B - 548a3d25dbf0
662 |
662 |
663 o 0 public a-A - 054250a37db4
663 o 0 public a-A - 054250a37db4
664
664
665 $ cd ../mu
665 $ cd ../mu
666 $ hgph # d6bcb4f74035 should have changed phase
666 $ hgph # d6bcb4f74035 should have changed phase
667 > # 145e75495359 is still draft. not ancestor of -r
667 > # 145e75495359 is still draft. not ancestor of -r
668 o 9 draft a-H - 967b449fbc94
668 o 9 draft a-H - 967b449fbc94
669 |
669 |
670 | o 8 public a-F - b740e3e5c05d
670 | o 8 public a-F - b740e3e5c05d
671 | |
671 | |
672 | o 7 public a-E - e9f537e46dea
672 | o 7 public a-E - e9f537e46dea
673 | |
673 | |
674 +---o 6 draft n-B - 145e75495359
674 +---o 6 draft n-B - 145e75495359
675 | |
675 | |
676 o | 5 public n-A - d6bcb4f74035
676 o | 5 public n-A - d6bcb4f74035
677 | |
677 | |
678 | o 4 public a-D - b555f63b6063
678 | o 4 public a-D - b555f63b6063
679 | |
679 | |
680 | o 3 public a-C - 54acac6f23ab
680 | o 3 public a-C - 54acac6f23ab
681 | |
681 | |
682 o | 2 public b-A - f54f1bb90ff3
682 o | 2 public b-A - f54f1bb90ff3
683 |/
683 |/
684 o 1 public a-B - 548a3d25dbf0
684 o 1 public a-B - 548a3d25dbf0
685 |
685 |
686 o 0 public a-A - 054250a37db4
686 o 0 public a-A - 054250a37db4
687
687
688
688
689
689
690 Pushing to Publish=True (common changeset from publish=False)
690 Pushing to Publish=True (common changeset from publish=False)
691
691
692 (in mu)
692 (in mu)
693 $ hg push ../alpha
693 $ hg push ../alpha
694 pushing to ../alpha
694 pushing to ../alpha
695 searching for changes
695 searching for changes
696 no changes found
696 no changes found
697 [1]
697 [1]
698 $ hgph
698 $ hgph
699 o 9 public a-H - 967b449fbc94
699 o 9 public a-H - 967b449fbc94
700 |
700 |
701 | o 8 public a-F - b740e3e5c05d
701 | o 8 public a-F - b740e3e5c05d
702 | |
702 | |
703 | o 7 public a-E - e9f537e46dea
703 | o 7 public a-E - e9f537e46dea
704 | |
704 | |
705 +---o 6 public n-B - 145e75495359
705 +---o 6 public n-B - 145e75495359
706 | |
706 | |
707 o | 5 public n-A - d6bcb4f74035
707 o | 5 public n-A - d6bcb4f74035
708 | |
708 | |
709 | o 4 public a-D - b555f63b6063
709 | o 4 public a-D - b555f63b6063
710 | |
710 | |
711 | o 3 public a-C - 54acac6f23ab
711 | o 3 public a-C - 54acac6f23ab
712 | |
712 | |
713 o | 2 public b-A - f54f1bb90ff3
713 o | 2 public b-A - f54f1bb90ff3
714 |/
714 |/
715 o 1 public a-B - 548a3d25dbf0
715 o 1 public a-B - 548a3d25dbf0
716 |
716 |
717 o 0 public a-A - 054250a37db4
717 o 0 public a-A - 054250a37db4
718
718
719 $ hgph -R ../alpha # a-H should have been synced to 0
719 $ hgph -R ../alpha # a-H should have been synced to 0
720 @ 10 public a-H - 967b449fbc94
720 @ 10 public a-H - 967b449fbc94
721 |
721 |
722 | o 9 draft a-G - 3e27b6f1eee1
722 | o 9 draft a-G - 3e27b6f1eee1
723 | |
723 | |
724 | o 8 public a-F - b740e3e5c05d
724 | o 8 public a-F - b740e3e5c05d
725 | |
725 | |
726 | o 7 public a-E - e9f537e46dea
726 | o 7 public a-E - e9f537e46dea
727 | |
727 | |
728 +---o 6 public n-B - 145e75495359
728 +---o 6 public n-B - 145e75495359
729 | |
729 | |
730 o | 5 public n-A - d6bcb4f74035
730 o | 5 public n-A - d6bcb4f74035
731 | |
731 | |
732 o | 4 public b-A - f54f1bb90ff3
732 o | 4 public b-A - f54f1bb90ff3
733 | |
733 | |
734 | o 3 public a-D - b555f63b6063
734 | o 3 public a-D - b555f63b6063
735 | |
735 | |
736 | o 2 public a-C - 54acac6f23ab
736 | o 2 public a-C - 54acac6f23ab
737 |/
737 |/
738 o 1 public a-B - 548a3d25dbf0
738 o 1 public a-B - 548a3d25dbf0
739 |
739 |
740 o 0 public a-A - 054250a37db4
740 o 0 public a-A - 054250a37db4
741
741
742
742
743
743
744 Discovery locally secret changeset on a remote repository:
744 Discovery locally secret changeset on a remote repository:
745
745
746 - should make it non-secret
746 - should make it non-secret
747
747
748 $ cd ../alpha
748 $ cd ../alpha
749 $ mkcommit A-secret --config phases.new-commit=2
749 $ mkcommit A-secret --config phases.new-commit=2
750 $ hgph
750 $ hgph
751 @ 11 secret A-secret - 435b5d83910c
751 @ 11 secret A-secret - 435b5d83910c
752 |
752 |
753 o 10 public a-H - 967b449fbc94
753 o 10 public a-H - 967b449fbc94
754 |
754 |
755 | o 9 draft a-G - 3e27b6f1eee1
755 | o 9 draft a-G - 3e27b6f1eee1
756 | |
756 | |
757 | o 8 public a-F - b740e3e5c05d
757 | o 8 public a-F - b740e3e5c05d
758 | |
758 | |
759 | o 7 public a-E - e9f537e46dea
759 | o 7 public a-E - e9f537e46dea
760 | |
760 | |
761 +---o 6 public n-B - 145e75495359
761 +---o 6 public n-B - 145e75495359
762 | |
762 | |
763 o | 5 public n-A - d6bcb4f74035
763 o | 5 public n-A - d6bcb4f74035
764 | |
764 | |
765 o | 4 public b-A - f54f1bb90ff3
765 o | 4 public b-A - f54f1bb90ff3
766 | |
766 | |
767 | o 3 public a-D - b555f63b6063
767 | o 3 public a-D - b555f63b6063
768 | |
768 | |
769 | o 2 public a-C - 54acac6f23ab
769 | o 2 public a-C - 54acac6f23ab
770 |/
770 |/
771 o 1 public a-B - 548a3d25dbf0
771 o 1 public a-B - 548a3d25dbf0
772 |
772 |
773 o 0 public a-A - 054250a37db4
773 o 0 public a-A - 054250a37db4
774
774
775 $ hg bundle --base 'parents(.)' -r . ../secret-bundle.hg
775 $ hg bundle --base 'parents(.)' -r . ../secret-bundle.hg
776 1 changesets found
776 1 changesets found
777 $ hg -R ../mu unbundle ../secret-bundle.hg
777 $ hg -R ../mu unbundle ../secret-bundle.hg
778 adding changesets
778 adding changesets
779 adding manifests
779 adding manifests
780 adding file changes
780 adding file changes
781 added 1 changesets with 1 changes to 1 files
781 added 1 changesets with 1 changes to 1 files
782 (run 'hg update' to get a working copy)
782 (run 'hg update' to get a working copy)
783 $ hgph -R ../mu
783 $ hgph -R ../mu
784 o 10 draft A-secret - 435b5d83910c
784 o 10 draft A-secret - 435b5d83910c
785 |
785 |
786 o 9 public a-H - 967b449fbc94
786 o 9 public a-H - 967b449fbc94
787 |
787 |
788 | o 8 public a-F - b740e3e5c05d
788 | o 8 public a-F - b740e3e5c05d
789 | |
789 | |
790 | o 7 public a-E - e9f537e46dea
790 | o 7 public a-E - e9f537e46dea
791 | |
791 | |
792 +---o 6 public n-B - 145e75495359
792 +---o 6 public n-B - 145e75495359
793 | |
793 | |
794 o | 5 public n-A - d6bcb4f74035
794 o | 5 public n-A - d6bcb4f74035
795 | |
795 | |
796 | o 4 public a-D - b555f63b6063
796 | o 4 public a-D - b555f63b6063
797 | |
797 | |
798 | o 3 public a-C - 54acac6f23ab
798 | o 3 public a-C - 54acac6f23ab
799 | |
799 | |
800 o | 2 public b-A - f54f1bb90ff3
800 o | 2 public b-A - f54f1bb90ff3
801 |/
801 |/
802 o 1 public a-B - 548a3d25dbf0
802 o 1 public a-B - 548a3d25dbf0
803 |
803 |
804 o 0 public a-A - 054250a37db4
804 o 0 public a-A - 054250a37db4
805
805
806 $ hg pull ../mu
806 $ hg pull ../mu
807 pulling from ../mu
807 pulling from ../mu
808 searching for changes
808 searching for changes
809 no changes found
809 no changes found
810 $ hgph
810 $ hgph
811 @ 11 draft A-secret - 435b5d83910c
811 @ 11 draft A-secret - 435b5d83910c
812 |
812 |
813 o 10 public a-H - 967b449fbc94
813 o 10 public a-H - 967b449fbc94
814 |
814 |
815 | o 9 draft a-G - 3e27b6f1eee1
815 | o 9 draft a-G - 3e27b6f1eee1
816 | |
816 | |
817 | o 8 public a-F - b740e3e5c05d
817 | o 8 public a-F - b740e3e5c05d
818 | |
818 | |
819 | o 7 public a-E - e9f537e46dea
819 | o 7 public a-E - e9f537e46dea
820 | |
820 | |
821 +---o 6 public n-B - 145e75495359
821 +---o 6 public n-B - 145e75495359
822 | |
822 | |
823 o | 5 public n-A - d6bcb4f74035
823 o | 5 public n-A - d6bcb4f74035
824 | |
824 | |
825 o | 4 public b-A - f54f1bb90ff3
825 o | 4 public b-A - f54f1bb90ff3
826 | |
826 | |
827 | o 3 public a-D - b555f63b6063
827 | o 3 public a-D - b555f63b6063
828 | |
828 | |
829 | o 2 public a-C - 54acac6f23ab
829 | o 2 public a-C - 54acac6f23ab
830 |/
830 |/
831 o 1 public a-B - 548a3d25dbf0
831 o 1 public a-B - 548a3d25dbf0
832 |
832 |
833 o 0 public a-A - 054250a37db4
833 o 0 public a-A - 054250a37db4
834
834
835
835
836 pushing a locally public and draft changesets remotly secret should make them appear on the remote side
836 pushing a locally public and draft changesets remotly secret should make them
837 appear on the remote side.
838
837
839
838 $ hg -R ../mu phase --secret --force 967b449fbc94
840 $ hg -R ../mu phase --secret --force 967b449fbc94
839 $ hg push -r 435b5d83910c ../mu
841 $ hg push -r 435b5d83910c ../mu
840 pushing to ../mu
842 pushing to ../mu
841 searching for changes
843 searching for changes
844 abort: push creates new remote head 435b5d83910c!
845 (did you forget to merge? use push -f to force)
846 [255]
847 $ hg push -fr 435b5d83910c ../mu # because the push will create new visible head
848 pushing to ../mu
849 searching for changes
842 adding changesets
850 adding changesets
843 adding manifests
851 adding manifests
844 adding file changes
852 adding file changes
845 added 0 changesets with 0 changes to 2 files
853 added 0 changesets with 0 changes to 2 files
846 $ hgph -R ../mu
854 $ hgph -R ../mu
847 o 10 draft A-secret - 435b5d83910c
855 o 10 draft A-secret - 435b5d83910c
848 |
856 |
849 o 9 public a-H - 967b449fbc94
857 o 9 public a-H - 967b449fbc94
850 |
858 |
851 | o 8 public a-F - b740e3e5c05d
859 | o 8 public a-F - b740e3e5c05d
852 | |
860 | |
853 | o 7 public a-E - e9f537e46dea
861 | o 7 public a-E - e9f537e46dea
854 | |
862 | |
855 +---o 6 public n-B - 145e75495359
863 +---o 6 public n-B - 145e75495359
856 | |
864 | |
857 o | 5 public n-A - d6bcb4f74035
865 o | 5 public n-A - d6bcb4f74035
858 | |
866 | |
859 | o 4 public a-D - b555f63b6063
867 | o 4 public a-D - b555f63b6063
860 | |
868 | |
861 | o 3 public a-C - 54acac6f23ab
869 | o 3 public a-C - 54acac6f23ab
862 | |
870 | |
863 o | 2 public b-A - f54f1bb90ff3
871 o | 2 public b-A - f54f1bb90ff3
864 |/
872 |/
865 o 1 public a-B - 548a3d25dbf0
873 o 1 public a-B - 548a3d25dbf0
866 |
874 |
867 o 0 public a-A - 054250a37db4
875 o 0 public a-A - 054250a37db4
868
876
869
877
870 pull new changeset with common draft locally
878 pull new changeset with common draft locally
871
879
872 $ hg up -q 967b449fbc94 # create a new root for draft
880 $ hg up -q 967b449fbc94 # create a new root for draft
873 $ mkcommit 'alpha-more'
881 $ mkcommit 'alpha-more'
874 created new head
882 created new head
875 $ hg push -fr . ../mu
883 $ hg push -fr . ../mu
876 pushing to ../mu
884 pushing to ../mu
877 searching for changes
885 searching for changes
878 adding changesets
886 adding changesets
879 adding manifests
887 adding manifests
880 adding file changes
888 adding file changes
881 added 1 changesets with 1 changes to 1 files (+1 heads)
889 added 1 changesets with 1 changes to 1 files (+1 heads)
882 $ cd ../mu
890 $ cd ../mu
883 $ hg phase --secret --force 1c5cfd894796
891 $ hg phase --secret --force 1c5cfd894796
884 $ hg up -q 435b5d83910c
892 $ hg up -q 435b5d83910c
885 $ mkcommit 'mu-more'
893 $ mkcommit 'mu-more'
886 $ cd ../alpha
894 $ cd ../alpha
887 $ hg pull ../mu
895 $ hg pull ../mu
888 pulling from ../mu
896 pulling from ../mu
889 searching for changes
897 searching for changes
890 adding changesets
898 adding changesets
891 adding manifests
899 adding manifests
892 adding file changes
900 adding file changes
893 added 1 changesets with 1 changes to 1 files
901 added 1 changesets with 1 changes to 1 files
894 (run 'hg update' to get a working copy)
902 (run 'hg update' to get a working copy)
895 $ hgph
903 $ hgph
896 o 13 draft mu-more - 5237fb433fc8
904 o 13 draft mu-more - 5237fb433fc8
897 |
905 |
898 | @ 12 draft alpha-more - 1c5cfd894796
906 | @ 12 draft alpha-more - 1c5cfd894796
899 | |
907 | |
900 o | 11 draft A-secret - 435b5d83910c
908 o | 11 draft A-secret - 435b5d83910c
901 |/
909 |/
902 o 10 public a-H - 967b449fbc94
910 o 10 public a-H - 967b449fbc94
903 |
911 |
904 | o 9 draft a-G - 3e27b6f1eee1
912 | o 9 draft a-G - 3e27b6f1eee1
905 | |
913 | |
906 | o 8 public a-F - b740e3e5c05d
914 | o 8 public a-F - b740e3e5c05d
907 | |
915 | |
908 | o 7 public a-E - e9f537e46dea
916 | o 7 public a-E - e9f537e46dea
909 | |
917 | |
910 +---o 6 public n-B - 145e75495359
918 +---o 6 public n-B - 145e75495359
911 | |
919 | |
912 o | 5 public n-A - d6bcb4f74035
920 o | 5 public n-A - d6bcb4f74035
913 | |
921 | |
914 o | 4 public b-A - f54f1bb90ff3
922 o | 4 public b-A - f54f1bb90ff3
915 | |
923 | |
916 | o 3 public a-D - b555f63b6063
924 | o 3 public a-D - b555f63b6063
917 | |
925 | |
918 | o 2 public a-C - 54acac6f23ab
926 | o 2 public a-C - 54acac6f23ab
919 |/
927 |/
920 o 1 public a-B - 548a3d25dbf0
928 o 1 public a-B - 548a3d25dbf0
921 |
929 |
922 o 0 public a-A - 054250a37db4
930 o 0 public a-A - 054250a37db4
923
931
924
932
925 Test that test are properly ignored on remote event when existing locally
933 Test that test are properly ignored on remote event when existing locally
926
934
927 $ cd ..
935 $ cd ..
928 $ hg clone -qU -r b555f63b6063 -r f54f1bb90ff3 beta gamma
936 $ hg clone -qU -r b555f63b6063 -r f54f1bb90ff3 beta gamma
929
937
930 # pathological case are
938 # pathological case are
931 #
939 #
932 # * secret remotely
940 # * secret remotely
933 # * known locally
941 # * known locally
934 # * repo have uncommon changeset
942 # * repo have uncommon changeset
935
943
936 $ hg -R beta phase --secret --force f54f1bb90ff3
944 $ hg -R beta phase --secret --force f54f1bb90ff3
937 $ hg -R gamma phase --draft --force f54f1bb90ff3
945 $ hg -R gamma phase --draft --force f54f1bb90ff3
938
946
939 $ cd gamma
947 $ cd gamma
940 $ hg pull ../beta
948 $ hg pull ../beta
941 pulling from ../beta
949 pulling from ../beta
942 searching for changes
950 searching for changes
943 adding changesets
951 adding changesets
944 adding manifests
952 adding manifests
945 adding file changes
953 adding file changes
946 added 2 changesets with 2 changes to 2 files
954 added 2 changesets with 2 changes to 2 files
947 (run 'hg update' to get a working copy)
955 (run 'hg update' to get a working copy)
948 $ hg phase f54f1bb90ff3
956 $ hg phase f54f1bb90ff3
949 2: draft
957 2: draft
950
958
951 same over the wire
959 same over the wire
952
960
953 $ cd ../beta
961 $ cd ../beta
954 $ hg serve -p $HGPORT -d --pid-file=../beta.pid -E ../beta-error.log
962 $ hg serve -p $HGPORT -d --pid-file=../beta.pid -E ../beta-error.log
955 $ cat ../beta.pid >> $DAEMON_PIDS
963 $ cat ../beta.pid >> $DAEMON_PIDS
956 $ cd ../gamma
964 $ cd ../gamma
957
965
958 $ hg pull http://localhost:$HGPORT/
966 $ hg pull http://localhost:$HGPORT/
959 pulling from http://localhost:$HGPORT/
967 pulling from http://localhost:$HGPORT/
960 searching for changes
968 searching for changes
961 no changes found
969 no changes found
962 $ hg phase f54f1bb90ff3
970 $ hg phase f54f1bb90ff3
963 2: draft
971 2: draft
964
972
965 check that secret local on both side are not synced to public
973 check that secret local on both side are not synced to public
966
974
967 $ hg push -r b555f63b6063 http://localhost:$HGPORT/
975 $ hg push -r b555f63b6063 http://localhost:$HGPORT/
968 pushing to http://localhost:$HGPORT/
976 pushing to http://localhost:$HGPORT/
969 searching for changes
977 searching for changes
970 no changes found
978 no changes found
971 [1]
979 [1]
972 $ hg phase f54f1bb90ff3
980 $ hg phase f54f1bb90ff3
973 2: draft
981 2: draft
974
982
975 put the changeset in the draft state again
983 put the changeset in the draft state again
976 (first test after this one expect to be able to copy)
984 (first test after this one expect to be able to copy)
977
985
978 $ cd ..
986 $ cd ..
979
987
980
988
981 Test Clone behavior
989 Test Clone behavior
982
990
983 A. Clone without secret changeset
991 A. Clone without secret changeset
984
992
985 1. cloning non-publishing repository
993 1. cloning non-publishing repository
986 (Phase should be preserved)
994 (Phase should be preserved)
987
995
988 # make sure there is no secret so we can use a copy clone
996 # make sure there is no secret so we can use a copy clone
989
997
990 $ hg -R mu phase --draft 'secret()'
998 $ hg -R mu phase --draft 'secret()'
991
999
992 $ hg clone -U mu Tau
1000 $ hg clone -U mu Tau
993 $ hgph -R Tau
1001 $ hgph -R Tau
994 o 12 draft mu-more - 5237fb433fc8
1002 o 12 draft mu-more - 5237fb433fc8
995 |
1003 |
996 | o 11 draft alpha-more - 1c5cfd894796
1004 | o 11 draft alpha-more - 1c5cfd894796
997 | |
1005 | |
998 o | 10 draft A-secret - 435b5d83910c
1006 o | 10 draft A-secret - 435b5d83910c
999 |/
1007 |/
1000 o 9 public a-H - 967b449fbc94
1008 o 9 public a-H - 967b449fbc94
1001 |
1009 |
1002 | o 8 public a-F - b740e3e5c05d
1010 | o 8 public a-F - b740e3e5c05d
1003 | |
1011 | |
1004 | o 7 public a-E - e9f537e46dea
1012 | o 7 public a-E - e9f537e46dea
1005 | |
1013 | |
1006 +---o 6 public n-B - 145e75495359
1014 +---o 6 public n-B - 145e75495359
1007 | |
1015 | |
1008 o | 5 public n-A - d6bcb4f74035
1016 o | 5 public n-A - d6bcb4f74035
1009 | |
1017 | |
1010 | o 4 public a-D - b555f63b6063
1018 | o 4 public a-D - b555f63b6063
1011 | |
1019 | |
1012 | o 3 public a-C - 54acac6f23ab
1020 | o 3 public a-C - 54acac6f23ab
1013 | |
1021 | |
1014 o | 2 public b-A - f54f1bb90ff3
1022 o | 2 public b-A - f54f1bb90ff3
1015 |/
1023 |/
1016 o 1 public a-B - 548a3d25dbf0
1024 o 1 public a-B - 548a3d25dbf0
1017 |
1025 |
1018 o 0 public a-A - 054250a37db4
1026 o 0 public a-A - 054250a37db4
1019
1027
1020
1028
1021 2. cloning publishing repository
1029 2. cloning publishing repository
1022
1030
1023 (everything should be public)
1031 (everything should be public)
1024
1032
1025 $ hg clone -U alpha Upsilon
1033 $ hg clone -U alpha Upsilon
1026 $ hgph -R Upsilon
1034 $ hgph -R Upsilon
1027 o 13 public mu-more - 5237fb433fc8
1035 o 13 public mu-more - 5237fb433fc8
1028 |
1036 |
1029 | o 12 public alpha-more - 1c5cfd894796
1037 | o 12 public alpha-more - 1c5cfd894796
1030 | |
1038 | |
1031 o | 11 public A-secret - 435b5d83910c
1039 o | 11 public A-secret - 435b5d83910c
1032 |/
1040 |/
1033 o 10 public a-H - 967b449fbc94
1041 o 10 public a-H - 967b449fbc94
1034 |
1042 |
1035 | o 9 public a-G - 3e27b6f1eee1
1043 | o 9 public a-G - 3e27b6f1eee1
1036 | |
1044 | |
1037 | o 8 public a-F - b740e3e5c05d
1045 | o 8 public a-F - b740e3e5c05d
1038 | |
1046 | |
1039 | o 7 public a-E - e9f537e46dea
1047 | o 7 public a-E - e9f537e46dea
1040 | |
1048 | |
1041 +---o 6 public n-B - 145e75495359
1049 +---o 6 public n-B - 145e75495359
1042 | |
1050 | |
1043 o | 5 public n-A - d6bcb4f74035
1051 o | 5 public n-A - d6bcb4f74035
1044 | |
1052 | |
1045 o | 4 public b-A - f54f1bb90ff3
1053 o | 4 public b-A - f54f1bb90ff3
1046 | |
1054 | |
1047 | o 3 public a-D - b555f63b6063
1055 | o 3 public a-D - b555f63b6063
1048 | |
1056 | |
1049 | o 2 public a-C - 54acac6f23ab
1057 | o 2 public a-C - 54acac6f23ab
1050 |/
1058 |/
1051 o 1 public a-B - 548a3d25dbf0
1059 o 1 public a-B - 548a3d25dbf0
1052 |
1060 |
1053 o 0 public a-A - 054250a37db4
1061 o 0 public a-A - 054250a37db4
1054
1062
1055
1063
@@ -1,435 +1,468 b''
1 $ hglog() { hg log --template "{rev} {phaseidx} {desc}\n" $*; }
1 $ hglog() { hg log --template "{rev} {phaseidx} {desc}\n" $*; }
2 $ mkcommit() {
2 $ mkcommit() {
3 > echo "$1" > "$1"
3 > echo "$1" > "$1"
4 > hg add "$1"
4 > hg add "$1"
5 > message="$1"
5 > message="$1"
6 > shift
6 > shift
7 > hg ci -m "$message" $*
7 > hg ci -m "$message" $*
8 > }
8 > }
9
9
10 $ hg init initialrepo
10 $ hg init initialrepo
11 $ cd initialrepo
11 $ cd initialrepo
12 $ mkcommit A
12 $ mkcommit A
13
13
14 New commit are draft by default
14 New commit are draft by default
15
15
16 $ hglog
16 $ hglog
17 0 1 A
17 0 1 A
18
18
19 Following commit are draft too
19 Following commit are draft too
20
20
21 $ mkcommit B
21 $ mkcommit B
22
22
23 $ hglog
23 $ hglog
24 1 1 B
24 1 1 B
25 0 1 A
25 0 1 A
26
26
27 Draft commit are properly created over public one:
27 Draft commit are properly created over public one:
28
28
29 $ hg phase --public .
29 $ hg phase --public .
30 $ hglog
30 $ hglog
31 1 0 B
31 1 0 B
32 0 0 A
32 0 0 A
33
33
34 $ mkcommit C
34 $ mkcommit C
35 $ mkcommit D
35 $ mkcommit D
36
36
37 $ hglog
37 $ hglog
38 3 1 D
38 3 1 D
39 2 1 C
39 2 1 C
40 1 0 B
40 1 0 B
41 0 0 A
41 0 0 A
42
42
43 Test creating changeset as secret
43 Test creating changeset as secret
44
44
45 $ mkcommit E --config phases.new-commit='secret'
45 $ mkcommit E --config phases.new-commit='secret'
46 $ hglog
46 $ hglog
47 4 2 E
47 4 2 E
48 3 1 D
48 3 1 D
49 2 1 C
49 2 1 C
50 1 0 B
50 1 0 B
51 0 0 A
51 0 0 A
52
52
53 Test the secret property is inherited
53 Test the secret property is inherited
54
54
55 $ mkcommit H
55 $ mkcommit H
56 $ hglog
56 $ hglog
57 5 2 H
57 5 2 H
58 4 2 E
58 4 2 E
59 3 1 D
59 3 1 D
60 2 1 C
60 2 1 C
61 1 0 B
61 1 0 B
62 0 0 A
62 0 0 A
63
63
64 Even on merge
64 Even on merge
65
65
66 $ hg up -q 1
66 $ hg up -q 1
67 $ mkcommit "B'"
67 $ mkcommit "B'"
68 created new head
68 created new head
69 $ hglog
69 $ hglog
70 6 1 B'
70 6 1 B'
71 5 2 H
71 5 2 H
72 4 2 E
72 4 2 E
73 3 1 D
73 3 1 D
74 2 1 C
74 2 1 C
75 1 0 B
75 1 0 B
76 0 0 A
76 0 0 A
77 $ hg merge 4 # E
77 $ hg merge 4 # E
78 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
78 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
79 (branch merge, don't forget to commit)
79 (branch merge, don't forget to commit)
80 $ hg ci -m "merge B' and E"
80 $ hg ci -m "merge B' and E"
81 $ hglog
81 $ hglog
82 7 2 merge B' and E
82 7 2 merge B' and E
83 6 1 B'
83 6 1 B'
84 5 2 H
84 5 2 H
85 4 2 E
85 4 2 E
86 3 1 D
86 3 1 D
87 2 1 C
87 2 1 C
88 1 0 B
88 1 0 B
89 0 0 A
89 0 0 A
90
90
91 Test secret changeset are not pushed
91 Test secret changeset are not pushed
92
92
93 $ hg init ../push-dest
93 $ hg init ../push-dest
94 $ cat > ../push-dest/.hg/hgrc << EOF
94 $ cat > ../push-dest/.hg/hgrc << EOF
95 > [phases]
95 > [phases]
96 > publish=False
96 > publish=False
97 > EOF
97 > EOF
98 $ hg outgoing ../push-dest --template='{rev} {phase} {desc|firstline}\n'
98 $ hg outgoing ../push-dest --template='{rev} {phase} {desc|firstline}\n'
99 comparing with ../push-dest
99 comparing with ../push-dest
100 searching for changes
100 searching for changes
101 0 public A
101 0 public A
102 1 public B
102 1 public B
103 2 draft C
103 2 draft C
104 3 draft D
104 3 draft D
105 6 draft B'
105 6 draft B'
106 $ hg outgoing -r default ../push-dest --template='{rev} {phase} {desc|firstline}\n'
106 $ hg outgoing -r default ../push-dest --template='{rev} {phase} {desc|firstline}\n'
107 comparing with ../push-dest
107 comparing with ../push-dest
108 searching for changes
108 searching for changes
109 0 public A
109 0 public A
110 1 public B
110 1 public B
111 2 draft C
111 2 draft C
112 3 draft D
112 3 draft D
113 6 draft B'
113 6 draft B'
114
114
115 $ hg push ../push-dest -f # force because we push multiple heads
115 $ hg push ../push-dest -f # force because we push multiple heads
116 pushing to ../push-dest
116 pushing to ../push-dest
117 searching for changes
117 searching for changes
118 adding changesets
118 adding changesets
119 adding manifests
119 adding manifests
120 adding file changes
120 adding file changes
121 added 5 changesets with 5 changes to 5 files (+1 heads)
121 added 5 changesets with 5 changes to 5 files (+1 heads)
122 $ hglog
122 $ hglog
123 7 2 merge B' and E
123 7 2 merge B' and E
124 6 1 B'
124 6 1 B'
125 5 2 H
125 5 2 H
126 4 2 E
126 4 2 E
127 3 1 D
127 3 1 D
128 2 1 C
128 2 1 C
129 1 0 B
129 1 0 B
130 0 0 A
130 0 0 A
131 $ cd ../push-dest
131 $ cd ../push-dest
132 $ hglog
132 $ hglog
133 4 1 B'
133 4 1 B'
134 3 1 D
134 3 1 D
135 2 1 C
135 2 1 C
136 1 0 B
136 1 0 B
137 0 0 A
137 0 0 A
138
139 (Issue3303)
140 Check that remote secret changeset are ignore when checking creation of remote heads
141
142 We add a secret head into the push destination. This secreat head shadow a
143 visible shared between the initial repo and the push destination.
144
145 $ hg up -q 4 # B'
146 $ mkcommit Z --config phases.new-commit=secret
147 $ hg phase .
148 5: secret
149
150 # We now try to push a new public changeset that descend from the common public
151 # head shadowed by the remote secret head.
152
153 $ cd ../initialrepo
154 $ hg up -q 6 #B'
155 $ mkcommit I
156 created new head
157 $ hg push ../push-dest
158 pushing to ../push-dest
159 searching for changes
160 adding changesets
161 adding manifests
162 adding file changes
163 added 1 changesets with 1 changes to 1 files (+1 heads)
164
165 :note: The "(+1 heads)" is wrong as we do not had any visible head
166
167
168 Restore condition prior extra insertion.
169 $ hg -q --config extensions.mq= strip .
170 $ hg up -q 7
138 $ cd ..
171 $ cd ..
139
172
140 Test secret changeset are not pull
173 Test secret changeset are not pull
141
174
142 $ hg init pull-dest
175 $ hg init pull-dest
143 $ cd pull-dest
176 $ cd pull-dest
144 $ hg pull ../initialrepo
177 $ hg pull ../initialrepo
145 pulling from ../initialrepo
178 pulling from ../initialrepo
146 requesting all changes
179 requesting all changes
147 adding changesets
180 adding changesets
148 adding manifests
181 adding manifests
149 adding file changes
182 adding file changes
150 added 5 changesets with 5 changes to 5 files (+1 heads)
183 added 5 changesets with 5 changes to 5 files (+1 heads)
151 (run 'hg heads' to see heads, 'hg merge' to merge)
184 (run 'hg heads' to see heads, 'hg merge' to merge)
152 $ hglog
185 $ hglog
153 4 0 B'
186 4 0 B'
154 3 0 D
187 3 0 D
155 2 0 C
188 2 0 C
156 1 0 B
189 1 0 B
157 0 0 A
190 0 0 A
158 $ cd ..
191 $ cd ..
159
192
160 But secret can still be bundled explicitly
193 But secret can still be bundled explicitly
161
194
162 $ cd initialrepo
195 $ cd initialrepo
163 $ hg bundle --base '4^' -r 'children(4)' ../secret-bundle.hg
196 $ hg bundle --base '4^' -r 'children(4)' ../secret-bundle.hg
164 4 changesets found
197 4 changesets found
165 $ cd ..
198 $ cd ..
166
199
167 Test secret changeset are not cloned
200 Test secret changeset are not cloned
168 (during local clone)
201 (during local clone)
169
202
170 $ hg clone -qU initialrepo clone-dest
203 $ hg clone -qU initialrepo clone-dest
171 $ hglog -R clone-dest
204 $ hglog -R clone-dest
172 4 0 B'
205 4 0 B'
173 3 0 D
206 3 0 D
174 2 0 C
207 2 0 C
175 1 0 B
208 1 0 B
176 0 0 A
209 0 0 A
177
210
178 Test revset
211 Test revset
179
212
180 $ cd initialrepo
213 $ cd initialrepo
181 $ hglog -r 'public()'
214 $ hglog -r 'public()'
182 0 0 A
215 0 0 A
183 1 0 B
216 1 0 B
184 $ hglog -r 'draft()'
217 $ hglog -r 'draft()'
185 2 1 C
218 2 1 C
186 3 1 D
219 3 1 D
187 6 1 B'
220 6 1 B'
188 $ hglog -r 'secret()'
221 $ hglog -r 'secret()'
189 4 2 E
222 4 2 E
190 5 2 H
223 5 2 H
191 7 2 merge B' and E
224 7 2 merge B' and E
192
225
193 test that phase are displayed in log at debug level
226 test that phase are displayed in log at debug level
194
227
195 $ hg log --debug
228 $ hg log --debug
196 changeset: 7:17a481b3bccb796c0521ae97903d81c52bfee4af
229 changeset: 7:17a481b3bccb796c0521ae97903d81c52bfee4af
197 tag: tip
230 tag: tip
198 phase: secret
231 phase: secret
199 parent: 6:cf9fe039dfd67e829edf6522a45de057b5c86519
232 parent: 6:cf9fe039dfd67e829edf6522a45de057b5c86519
200 parent: 4:a603bfb5a83e312131cebcd05353c217d4d21dde
233 parent: 4:a603bfb5a83e312131cebcd05353c217d4d21dde
201 manifest: 7:5e724ffacba267b2ab726c91fc8b650710deaaa8
234 manifest: 7:5e724ffacba267b2ab726c91fc8b650710deaaa8
202 user: test
235 user: test
203 date: Thu Jan 01 00:00:00 1970 +0000
236 date: Thu Jan 01 00:00:00 1970 +0000
204 files+: C D E
237 files+: C D E
205 extra: branch=default
238 extra: branch=default
206 description:
239 description:
207 merge B' and E
240 merge B' and E
208
241
209
242
210 changeset: 6:cf9fe039dfd67e829edf6522a45de057b5c86519
243 changeset: 6:cf9fe039dfd67e829edf6522a45de057b5c86519
211 phase: draft
244 phase: draft
212 parent: 1:27547f69f25460a52fff66ad004e58da7ad3fb56
245 parent: 1:27547f69f25460a52fff66ad004e58da7ad3fb56
213 parent: -1:0000000000000000000000000000000000000000
246 parent: -1:0000000000000000000000000000000000000000
214 manifest: 6:ab8bfef2392903058bf4ebb9e7746e8d7026b27a
247 manifest: 6:ab8bfef2392903058bf4ebb9e7746e8d7026b27a
215 user: test
248 user: test
216 date: Thu Jan 01 00:00:00 1970 +0000
249 date: Thu Jan 01 00:00:00 1970 +0000
217 files+: B'
250 files+: B'
218 extra: branch=default
251 extra: branch=default
219 description:
252 description:
220 B'
253 B'
221
254
222
255
223 changeset: 5:a030c6be5127abc010fcbff1851536552e6951a8
256 changeset: 5:a030c6be5127abc010fcbff1851536552e6951a8
224 phase: secret
257 phase: secret
225 parent: 4:a603bfb5a83e312131cebcd05353c217d4d21dde
258 parent: 4:a603bfb5a83e312131cebcd05353c217d4d21dde
226 parent: -1:0000000000000000000000000000000000000000
259 parent: -1:0000000000000000000000000000000000000000
227 manifest: 5:5c710aa854874fe3d5fa7192e77bdb314cc08b5a
260 manifest: 5:5c710aa854874fe3d5fa7192e77bdb314cc08b5a
228 user: test
261 user: test
229 date: Thu Jan 01 00:00:00 1970 +0000
262 date: Thu Jan 01 00:00:00 1970 +0000
230 files+: H
263 files+: H
231 extra: branch=default
264 extra: branch=default
232 description:
265 description:
233 H
266 H
234
267
235
268
236 changeset: 4:a603bfb5a83e312131cebcd05353c217d4d21dde
269 changeset: 4:a603bfb5a83e312131cebcd05353c217d4d21dde
237 phase: secret
270 phase: secret
238 parent: 3:b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e
271 parent: 3:b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e
239 parent: -1:0000000000000000000000000000000000000000
272 parent: -1:0000000000000000000000000000000000000000
240 manifest: 4:7173fd1c27119750b959e3a0f47ed78abe75d6dc
273 manifest: 4:7173fd1c27119750b959e3a0f47ed78abe75d6dc
241 user: test
274 user: test
242 date: Thu Jan 01 00:00:00 1970 +0000
275 date: Thu Jan 01 00:00:00 1970 +0000
243 files+: E
276 files+: E
244 extra: branch=default
277 extra: branch=default
245 description:
278 description:
246 E
279 E
247
280
248
281
249 changeset: 3:b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e
282 changeset: 3:b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e
250 phase: draft
283 phase: draft
251 parent: 2:f838bfaca5c7226600ebcfd84f3c3c13a28d3757
284 parent: 2:f838bfaca5c7226600ebcfd84f3c3c13a28d3757
252 parent: -1:0000000000000000000000000000000000000000
285 parent: -1:0000000000000000000000000000000000000000
253 manifest: 3:6e1f4c47ecb533ffd0c8e52cdc88afb6cd39e20c
286 manifest: 3:6e1f4c47ecb533ffd0c8e52cdc88afb6cd39e20c
254 user: test
287 user: test
255 date: Thu Jan 01 00:00:00 1970 +0000
288 date: Thu Jan 01 00:00:00 1970 +0000
256 files+: D
289 files+: D
257 extra: branch=default
290 extra: branch=default
258 description:
291 description:
259 D
292 D
260
293
261
294
262 changeset: 2:f838bfaca5c7226600ebcfd84f3c3c13a28d3757
295 changeset: 2:f838bfaca5c7226600ebcfd84f3c3c13a28d3757
263 phase: draft
296 phase: draft
264 parent: 1:27547f69f25460a52fff66ad004e58da7ad3fb56
297 parent: 1:27547f69f25460a52fff66ad004e58da7ad3fb56
265 parent: -1:0000000000000000000000000000000000000000
298 parent: -1:0000000000000000000000000000000000000000
266 manifest: 2:66a5a01817fdf5239c273802b5b7618d051c89e4
299 manifest: 2:66a5a01817fdf5239c273802b5b7618d051c89e4
267 user: test
300 user: test
268 date: Thu Jan 01 00:00:00 1970 +0000
301 date: Thu Jan 01 00:00:00 1970 +0000
269 files+: C
302 files+: C
270 extra: branch=default
303 extra: branch=default
271 description:
304 description:
272 C
305 C
273
306
274
307
275 changeset: 1:27547f69f25460a52fff66ad004e58da7ad3fb56
308 changeset: 1:27547f69f25460a52fff66ad004e58da7ad3fb56
276 parent: 0:4a2df7238c3b48766b5e22fafbb8a2f506ec8256
309 parent: 0:4a2df7238c3b48766b5e22fafbb8a2f506ec8256
277 parent: -1:0000000000000000000000000000000000000000
310 parent: -1:0000000000000000000000000000000000000000
278 manifest: 1:cb5cbbc1bfbf24cc34b9e8c16914e9caa2d2a7fd
311 manifest: 1:cb5cbbc1bfbf24cc34b9e8c16914e9caa2d2a7fd
279 user: test
312 user: test
280 date: Thu Jan 01 00:00:00 1970 +0000
313 date: Thu Jan 01 00:00:00 1970 +0000
281 files+: B
314 files+: B
282 extra: branch=default
315 extra: branch=default
283 description:
316 description:
284 B
317 B
285
318
286
319
287 changeset: 0:4a2df7238c3b48766b5e22fafbb8a2f506ec8256
320 changeset: 0:4a2df7238c3b48766b5e22fafbb8a2f506ec8256
288 parent: -1:0000000000000000000000000000000000000000
321 parent: -1:0000000000000000000000000000000000000000
289 parent: -1:0000000000000000000000000000000000000000
322 parent: -1:0000000000000000000000000000000000000000
290 manifest: 0:007d8c9d88841325f5c6b06371b35b4e8a2b1a83
323 manifest: 0:007d8c9d88841325f5c6b06371b35b4e8a2b1a83
291 user: test
324 user: test
292 date: Thu Jan 01 00:00:00 1970 +0000
325 date: Thu Jan 01 00:00:00 1970 +0000
293 files+: A
326 files+: A
294 extra: branch=default
327 extra: branch=default
295 description:
328 description:
296 A
329 A
297
330
298
331
299
332
300 Test phase command
333 Test phase command
301 ===================
334 ===================
302
335
303 initial picture
336 initial picture
304
337
305 $ cat >> $HGRCPATH << EOF
338 $ cat >> $HGRCPATH << EOF
306 > [extensions]
339 > [extensions]
307 > hgext.graphlog=
340 > hgext.graphlog=
308 > EOF
341 > EOF
309 $ hg log -G --template "{rev} {phase} {desc}\n"
342 $ hg log -G --template "{rev} {phase} {desc}\n"
310 @ 7 secret merge B' and E
343 @ 7 secret merge B' and E
311 |\
344 |\
312 | o 6 draft B'
345 | o 6 draft B'
313 | |
346 | |
314 +---o 5 secret H
347 +---o 5 secret H
315 | |
348 | |
316 o | 4 secret E
349 o | 4 secret E
317 | |
350 | |
318 o | 3 draft D
351 o | 3 draft D
319 | |
352 | |
320 o | 2 draft C
353 o | 2 draft C
321 |/
354 |/
322 o 1 public B
355 o 1 public B
323 |
356 |
324 o 0 public A
357 o 0 public A
325
358
326
359
327 display changesets phase
360 display changesets phase
328
361
329 (mixing -r and plain rev specification)
362 (mixing -r and plain rev specification)
330
363
331 $ hg phase 1::4 -r 7
364 $ hg phase 1::4 -r 7
332 1: public
365 1: public
333 2: draft
366 2: draft
334 3: draft
367 3: draft
335 4: secret
368 4: secret
336 7: secret
369 7: secret
337
370
338
371
339 move changeset forward
372 move changeset forward
340
373
341 (with -r option)
374 (with -r option)
342
375
343 $ hg phase --public -r 2
376 $ hg phase --public -r 2
344 $ hg log -G --template "{rev} {phase} {desc}\n"
377 $ hg log -G --template "{rev} {phase} {desc}\n"
345 @ 7 secret merge B' and E
378 @ 7 secret merge B' and E
346 |\
379 |\
347 | o 6 draft B'
380 | o 6 draft B'
348 | |
381 | |
349 +---o 5 secret H
382 +---o 5 secret H
350 | |
383 | |
351 o | 4 secret E
384 o | 4 secret E
352 | |
385 | |
353 o | 3 draft D
386 o | 3 draft D
354 | |
387 | |
355 o | 2 public C
388 o | 2 public C
356 |/
389 |/
357 o 1 public B
390 o 1 public B
358 |
391 |
359 o 0 public A
392 o 0 public A
360
393
361
394
362 move changeset backward
395 move changeset backward
363
396
364 (without -r option)
397 (without -r option)
365
398
366 $ hg phase --draft --force 2
399 $ hg phase --draft --force 2
367 $ hg log -G --template "{rev} {phase} {desc}\n"
400 $ hg log -G --template "{rev} {phase} {desc}\n"
368 @ 7 secret merge B' and E
401 @ 7 secret merge B' and E
369 |\
402 |\
370 | o 6 draft B'
403 | o 6 draft B'
371 | |
404 | |
372 +---o 5 secret H
405 +---o 5 secret H
373 | |
406 | |
374 o | 4 secret E
407 o | 4 secret E
375 | |
408 | |
376 o | 3 draft D
409 o | 3 draft D
377 | |
410 | |
378 o | 2 draft C
411 o | 2 draft C
379 |/
412 |/
380 o 1 public B
413 o 1 public B
381 |
414 |
382 o 0 public A
415 o 0 public A
383
416
384
417
385 move changeset forward and backward
418 move changeset forward and backward
386
419
387 $ hg phase --draft --force 1::4
420 $ hg phase --draft --force 1::4
388 $ hg log -G --template "{rev} {phase} {desc}\n"
421 $ hg log -G --template "{rev} {phase} {desc}\n"
389 @ 7 secret merge B' and E
422 @ 7 secret merge B' and E
390 |\
423 |\
391 | o 6 draft B'
424 | o 6 draft B'
392 | |
425 | |
393 +---o 5 secret H
426 +---o 5 secret H
394 | |
427 | |
395 o | 4 draft E
428 o | 4 draft E
396 | |
429 | |
397 o | 3 draft D
430 o | 3 draft D
398 | |
431 | |
399 o | 2 draft C
432 o | 2 draft C
400 |/
433 |/
401 o 1 draft B
434 o 1 draft B
402 |
435 |
403 o 0 public A
436 o 0 public A
404
437
405 test partial failure
438 test partial failure
406
439
407 $ hg phase --public 7
440 $ hg phase --public 7
408 $ hg phase --draft '5 or 7'
441 $ hg phase --draft '5 or 7'
409 cannot move 1 changesets to a more permissive phase, use --force
442 cannot move 1 changesets to a more permissive phase, use --force
410 phase changed for 1 changesets
443 phase changed for 1 changesets
411 [1]
444 [1]
412 $ hg log -G --template "{rev} {phase} {desc}\n"
445 $ hg log -G --template "{rev} {phase} {desc}\n"
413 @ 7 public merge B' and E
446 @ 7 public merge B' and E
414 |\
447 |\
415 | o 6 public B'
448 | o 6 public B'
416 | |
449 | |
417 +---o 5 draft H
450 +---o 5 draft H
418 | |
451 | |
419 o | 4 public E
452 o | 4 public E
420 | |
453 | |
421 o | 3 public D
454 o | 3 public D
422 | |
455 | |
423 o | 2 public C
456 o | 2 public C
424 |/
457 |/
425 o 1 public B
458 o 1 public B
426 |
459 |
427 o 0 public A
460 o 0 public A
428
461
429
462
430 test complete failure
463 test complete failure
431
464
432 $ hg phase --draft 7
465 $ hg phase --draft 7
433 cannot move 1 changesets to a more permissive phase, use --force
466 cannot move 1 changesets to a more permissive phase, use --force
434 no phases changed
467 no phases changed
435 [1]
468 [1]
General Comments 0
You need to be logged in to leave comments. Login now