##// END OF EJS Templates
destutil: make messages at updating to the closed head usual form...
FUJIWARA Katsunori -
r28683:d0210a35 default
parent child Browse files
Show More
@@ -1,422 +1,422 b''
1 # destutil.py - Mercurial utility function for command destination
1 # destutil.py - Mercurial utility function for command destination
2 #
2 #
3 # Copyright Matt Mackall <mpm@selenic.com> and other
3 # Copyright Matt Mackall <mpm@selenic.com> and other
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 __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 from .i18n import _
10 from .i18n import _
11 from . import (
11 from . import (
12 bookmarks,
12 bookmarks,
13 error,
13 error,
14 obsolete,
14 obsolete,
15 )
15 )
16
16
17 def _destupdatevalidate(repo, rev, clean, check):
17 def _destupdatevalidate(repo, rev, clean, check):
18 """validate that the destination comply to various rules
18 """validate that the destination comply to various rules
19
19
20 This exists as its own function to help wrapping from extensions."""
20 This exists as its own function to help wrapping from extensions."""
21 wc = repo[None]
21 wc = repo[None]
22 p1 = wc.p1()
22 p1 = wc.p1()
23 if not clean:
23 if not clean:
24 # Check that the update is linear.
24 # Check that the update is linear.
25 #
25 #
26 # Mercurial do not allow update-merge for non linear pattern
26 # Mercurial do not allow update-merge for non linear pattern
27 # (that would be technically possible but was considered too confusing
27 # (that would be technically possible but was considered too confusing
28 # for user a long time ago)
28 # for user a long time ago)
29 #
29 #
30 # See mercurial.merge.update for details
30 # See mercurial.merge.update for details
31 if p1.rev() not in repo.changelog.ancestors([rev], inclusive=True):
31 if p1.rev() not in repo.changelog.ancestors([rev], inclusive=True):
32 dirty = wc.dirty(missing=True)
32 dirty = wc.dirty(missing=True)
33 foreground = obsolete.foreground(repo, [p1.node()])
33 foreground = obsolete.foreground(repo, [p1.node()])
34 if not repo[rev].node() in foreground:
34 if not repo[rev].node() in foreground:
35 if dirty:
35 if dirty:
36 msg = _("uncommitted changes")
36 msg = _("uncommitted changes")
37 hint = _("commit and merge, or update --clean to"
37 hint = _("commit and merge, or update --clean to"
38 " discard changes")
38 " discard changes")
39 raise error.UpdateAbort(msg, hint=hint)
39 raise error.UpdateAbort(msg, hint=hint)
40 elif not check: # destination is not a descendant.
40 elif not check: # destination is not a descendant.
41 msg = _("not a linear update")
41 msg = _("not a linear update")
42 hint = _("merge or update --check to force update")
42 hint = _("merge or update --check to force update")
43 raise error.UpdateAbort(msg, hint=hint)
43 raise error.UpdateAbort(msg, hint=hint)
44
44
45 def _destupdateobs(repo, clean, check):
45 def _destupdateobs(repo, clean, check):
46 """decide of an update destination from obsolescence markers"""
46 """decide of an update destination from obsolescence markers"""
47 node = None
47 node = None
48 wc = repo[None]
48 wc = repo[None]
49 p1 = wc.p1()
49 p1 = wc.p1()
50 movemark = None
50 movemark = None
51
51
52 if p1.obsolete() and not p1.children():
52 if p1.obsolete() and not p1.children():
53 # allow updating to successors
53 # allow updating to successors
54 successors = obsolete.successorssets(repo, p1.node())
54 successors = obsolete.successorssets(repo, p1.node())
55
55
56 # behavior of certain cases is as follows,
56 # behavior of certain cases is as follows,
57 #
57 #
58 # divergent changesets: update to highest rev, similar to what
58 # divergent changesets: update to highest rev, similar to what
59 # is currently done when there are more than one head
59 # is currently done when there are more than one head
60 # (i.e. 'tip')
60 # (i.e. 'tip')
61 #
61 #
62 # replaced changesets: same as divergent except we know there
62 # replaced changesets: same as divergent except we know there
63 # is no conflict
63 # is no conflict
64 #
64 #
65 # pruned changeset: no update is done; though, we could
65 # pruned changeset: no update is done; though, we could
66 # consider updating to the first non-obsolete parent,
66 # consider updating to the first non-obsolete parent,
67 # similar to what is current done for 'hg prune'
67 # similar to what is current done for 'hg prune'
68
68
69 if successors:
69 if successors:
70 # flatten the list here handles both divergent (len > 1)
70 # flatten the list here handles both divergent (len > 1)
71 # and the usual case (len = 1)
71 # and the usual case (len = 1)
72 successors = [n for sub in successors for n in sub]
72 successors = [n for sub in successors for n in sub]
73
73
74 # get the max revision for the given successors set,
74 # get the max revision for the given successors set,
75 # i.e. the 'tip' of a set
75 # i.e. the 'tip' of a set
76 node = repo.revs('max(%ln)', successors).first()
76 node = repo.revs('max(%ln)', successors).first()
77 if bookmarks.isactivewdirparent(repo):
77 if bookmarks.isactivewdirparent(repo):
78 movemark = repo['.'].node()
78 movemark = repo['.'].node()
79 return node, movemark, None
79 return node, movemark, None
80
80
81 def _destupdatebook(repo, clean, check):
81 def _destupdatebook(repo, clean, check):
82 """decide on an update destination from active bookmark"""
82 """decide on an update destination from active bookmark"""
83 # we also move the active bookmark, if any
83 # we also move the active bookmark, if any
84 activemark = None
84 activemark = None
85 node, movemark = bookmarks.calculateupdate(repo.ui, repo, None)
85 node, movemark = bookmarks.calculateupdate(repo.ui, repo, None)
86 if node is not None:
86 if node is not None:
87 activemark = node
87 activemark = node
88 return node, movemark, activemark
88 return node, movemark, activemark
89
89
90 def _destupdatebranch(repo, clean, check):
90 def _destupdatebranch(repo, clean, check):
91 """decide on an update destination from current branch
91 """decide on an update destination from current branch
92
92
93 This ignores closed branch heads.
93 This ignores closed branch heads.
94 """
94 """
95 wc = repo[None]
95 wc = repo[None]
96 movemark = node = None
96 movemark = node = None
97 currentbranch = wc.branch()
97 currentbranch = wc.branch()
98 if currentbranch in repo.branchmap():
98 if currentbranch in repo.branchmap():
99 heads = repo.branchheads(currentbranch)
99 heads = repo.branchheads(currentbranch)
100 if heads:
100 if heads:
101 node = repo.revs('max(.::(%ln))', heads).first()
101 node = repo.revs('max(.::(%ln))', heads).first()
102 if bookmarks.isactivewdirparent(repo):
102 if bookmarks.isactivewdirparent(repo):
103 movemark = repo['.'].node()
103 movemark = repo['.'].node()
104 else:
104 else:
105 if currentbranch == 'default': # no default branch!
105 if currentbranch == 'default': # no default branch!
106 # update to the tipmost non-closed branch head
106 # update to the tipmost non-closed branch head
107 node = repo.revs('max(head() and not closed())').first()
107 node = repo.revs('max(head() and not closed())').first()
108 else:
108 else:
109 raise error.Abort(_("branch %s not found") % currentbranch)
109 raise error.Abort(_("branch %s not found") % currentbranch)
110 return node, movemark, None
110 return node, movemark, None
111
111
112 def _destupdatebranchfallback(repo, clean, check):
112 def _destupdatebranchfallback(repo, clean, check):
113 """decide on an update destination from closed heads in current branch"""
113 """decide on an update destination from closed heads in current branch"""
114 wc = repo[None]
114 wc = repo[None]
115 currentbranch = wc.branch()
115 currentbranch = wc.branch()
116 movemark = None
116 movemark = None
117 if currentbranch in repo.branchmap():
117 if currentbranch in repo.branchmap():
118 # here, all descendant branch heads are closed
118 # here, all descendant branch heads are closed
119 heads = repo.branchheads(currentbranch, closed=True)
119 heads = repo.branchheads(currentbranch, closed=True)
120 assert heads, "any branch has at least one head"
120 assert heads, "any branch has at least one head"
121 node = repo.revs('max(.::(%ln))', heads).first()
121 node = repo.revs('max(.::(%ln))', heads).first()
122 assert node is not None, ("any revision has at least "
122 assert node is not None, ("any revision has at least "
123 "one descendant branch head")
123 "one descendant branch head")
124 if bookmarks.isactivewdirparent(repo):
124 if bookmarks.isactivewdirparent(repo):
125 movemark = repo['.'].node()
125 movemark = repo['.'].node()
126 else:
126 else:
127 # here, no "default" branch, and all branches are closed
127 # here, no "default" branch, and all branches are closed
128 node = repo.lookup('tip')
128 node = repo.lookup('tip')
129 assert node is not None, "'tip' exists even in empty repository"
129 assert node is not None, "'tip' exists even in empty repository"
130 return node, movemark, None
130 return node, movemark, None
131
131
132 # order in which each step should be evalutated
132 # order in which each step should be evalutated
133 # steps are run until one finds a destination
133 # steps are run until one finds a destination
134 destupdatesteps = ['evolution', 'bookmark', 'branch', 'branchfallback']
134 destupdatesteps = ['evolution', 'bookmark', 'branch', 'branchfallback']
135 # mapping to ease extension overriding steps.
135 # mapping to ease extension overriding steps.
136 destupdatestepmap = {'evolution': _destupdateobs,
136 destupdatestepmap = {'evolution': _destupdateobs,
137 'bookmark': _destupdatebook,
137 'bookmark': _destupdatebook,
138 'branch': _destupdatebranch,
138 'branch': _destupdatebranch,
139 'branchfallback': _destupdatebranchfallback,
139 'branchfallback': _destupdatebranchfallback,
140 }
140 }
141
141
142 def destupdate(repo, clean=False, check=False):
142 def destupdate(repo, clean=False, check=False):
143 """destination for bare update operation
143 """destination for bare update operation
144
144
145 return (rev, movemark, activemark)
145 return (rev, movemark, activemark)
146
146
147 - rev: the revision to update to,
147 - rev: the revision to update to,
148 - movemark: node to move the active bookmark from
148 - movemark: node to move the active bookmark from
149 (cf bookmark.calculate update),
149 (cf bookmark.calculate update),
150 - activemark: a bookmark to activate at the end of the update.
150 - activemark: a bookmark to activate at the end of the update.
151 """
151 """
152 node = movemark = activemark = None
152 node = movemark = activemark = None
153
153
154 for step in destupdatesteps:
154 for step in destupdatesteps:
155 node, movemark, activemark = destupdatestepmap[step](repo, clean, check)
155 node, movemark, activemark = destupdatestepmap[step](repo, clean, check)
156 if node is not None:
156 if node is not None:
157 break
157 break
158 rev = repo[node].rev()
158 rev = repo[node].rev()
159
159
160 _destupdatevalidate(repo, rev, clean, check)
160 _destupdatevalidate(repo, rev, clean, check)
161
161
162 return rev, movemark, activemark
162 return rev, movemark, activemark
163
163
164 msgdestmerge = {
164 msgdestmerge = {
165 # too many matching divergent bookmark
165 # too many matching divergent bookmark
166 'toomanybookmarks':
166 'toomanybookmarks':
167 {'merge':
167 {'merge':
168 (_("multiple matching bookmarks to merge -"
168 (_("multiple matching bookmarks to merge -"
169 " please merge with an explicit rev or bookmark"),
169 " please merge with an explicit rev or bookmark"),
170 _("run 'hg heads' to see all heads")),
170 _("run 'hg heads' to see all heads")),
171 'rebase':
171 'rebase':
172 (_("multiple matching bookmarks to rebase -"
172 (_("multiple matching bookmarks to rebase -"
173 " please rebase to an explicit rev or bookmark"),
173 " please rebase to an explicit rev or bookmark"),
174 _("run 'hg heads' to see all heads")),
174 _("run 'hg heads' to see all heads")),
175 },
175 },
176 # no other matching divergent bookmark
176 # no other matching divergent bookmark
177 'nootherbookmarks':
177 'nootherbookmarks':
178 {'merge':
178 {'merge':
179 (_("no matching bookmark to merge - "
179 (_("no matching bookmark to merge - "
180 "please merge with an explicit rev or bookmark"),
180 "please merge with an explicit rev or bookmark"),
181 _("run 'hg heads' to see all heads")),
181 _("run 'hg heads' to see all heads")),
182 'rebase':
182 'rebase':
183 (_("no matching bookmark to rebase - "
183 (_("no matching bookmark to rebase - "
184 "please rebase to an explicit rev or bookmark"),
184 "please rebase to an explicit rev or bookmark"),
185 _("run 'hg heads' to see all heads")),
185 _("run 'hg heads' to see all heads")),
186 },
186 },
187 # branch have too many unbookmarked heads, no obvious destination
187 # branch have too many unbookmarked heads, no obvious destination
188 'toomanyheads':
188 'toomanyheads':
189 {'merge':
189 {'merge':
190 (_("branch '%s' has %d heads - please merge with an explicit rev"),
190 (_("branch '%s' has %d heads - please merge with an explicit rev"),
191 _("run 'hg heads .' to see heads")),
191 _("run 'hg heads .' to see heads")),
192 'rebase':
192 'rebase':
193 (_("branch '%s' has %d heads - please rebase to an explicit rev"),
193 (_("branch '%s' has %d heads - please rebase to an explicit rev"),
194 _("run 'hg heads .' to see heads")),
194 _("run 'hg heads .' to see heads")),
195 },
195 },
196 # branch have no other unbookmarked heads
196 # branch have no other unbookmarked heads
197 'bookmarkedheads':
197 'bookmarkedheads':
198 {'merge':
198 {'merge':
199 (_("heads are bookmarked - please merge with an explicit rev"),
199 (_("heads are bookmarked - please merge with an explicit rev"),
200 _("run 'hg heads' to see all heads")),
200 _("run 'hg heads' to see all heads")),
201 'rebase':
201 'rebase':
202 (_("heads are bookmarked - please rebase to an explicit rev"),
202 (_("heads are bookmarked - please rebase to an explicit rev"),
203 _("run 'hg heads' to see all heads")),
203 _("run 'hg heads' to see all heads")),
204 },
204 },
205 # branch have just a single heads, but there is other branches
205 # branch have just a single heads, but there is other branches
206 'nootherbranchheads':
206 'nootherbranchheads':
207 {'merge':
207 {'merge':
208 (_("branch '%s' has one head - please merge with an explicit rev"),
208 (_("branch '%s' has one head - please merge with an explicit rev"),
209 _("run 'hg heads' to see all heads")),
209 _("run 'hg heads' to see all heads")),
210 'rebase':
210 'rebase':
211 (_("branch '%s' has one head - please rebase to an explicit rev"),
211 (_("branch '%s' has one head - please rebase to an explicit rev"),
212 _("run 'hg heads' to see all heads")),
212 _("run 'hg heads' to see all heads")),
213 },
213 },
214 # repository have a single head
214 # repository have a single head
215 'nootherheads':
215 'nootherheads':
216 {'merge':
216 {'merge':
217 (_('nothing to merge'),
217 (_('nothing to merge'),
218 None),
218 None),
219 'rebase':
219 'rebase':
220 (_('nothing to rebase'),
220 (_('nothing to rebase'),
221 None),
221 None),
222 },
222 },
223 # repository have a single head and we are not on it
223 # repository have a single head and we are not on it
224 'nootherheadsbehind':
224 'nootherheadsbehind':
225 {'merge':
225 {'merge':
226 (_('nothing to merge'),
226 (_('nothing to merge'),
227 _("use 'hg update' instead")),
227 _("use 'hg update' instead")),
228 'rebase':
228 'rebase':
229 (_('nothing to rebase'),
229 (_('nothing to rebase'),
230 _("use 'hg update' instead")),
230 _("use 'hg update' instead")),
231 },
231 },
232 # We are not on a head
232 # We are not on a head
233 'notatheads':
233 'notatheads':
234 {'merge':
234 {'merge':
235 (_('working directory not at a head revision'),
235 (_('working directory not at a head revision'),
236 _("use 'hg update' or merge with an explicit revision")),
236 _("use 'hg update' or merge with an explicit revision")),
237 'rebase':
237 'rebase':
238 (_('working directory not at a head revision'),
238 (_('working directory not at a head revision'),
239 _("use 'hg update' or rebase to an explicit revision"))
239 _("use 'hg update' or rebase to an explicit revision"))
240 },
240 },
241 'emptysourceset':
241 'emptysourceset':
242 {'merge':
242 {'merge':
243 (_('source set is empty'),
243 (_('source set is empty'),
244 None),
244 None),
245 'rebase':
245 'rebase':
246 (_('source set is empty'),
246 (_('source set is empty'),
247 None),
247 None),
248 },
248 },
249 'multiplebranchessourceset':
249 'multiplebranchessourceset':
250 {'merge':
250 {'merge':
251 (_('source set is rooted in multiple branches'),
251 (_('source set is rooted in multiple branches'),
252 None),
252 None),
253 'rebase':
253 'rebase':
254 (_('rebaseset is rooted in multiple named branches'),
254 (_('rebaseset is rooted in multiple named branches'),
255 _('specify an explicit destination with --dest')),
255 _('specify an explicit destination with --dest')),
256 },
256 },
257 }
257 }
258
258
259 def _destmergebook(repo, action='merge', sourceset=None):
259 def _destmergebook(repo, action='merge', sourceset=None):
260 """find merge destination in the active bookmark case"""
260 """find merge destination in the active bookmark case"""
261 node = None
261 node = None
262 bmheads = repo.bookmarkheads(repo._activebookmark)
262 bmheads = repo.bookmarkheads(repo._activebookmark)
263 curhead = repo[repo._activebookmark].node()
263 curhead = repo[repo._activebookmark].node()
264 if len(bmheads) == 2:
264 if len(bmheads) == 2:
265 if curhead == bmheads[0]:
265 if curhead == bmheads[0]:
266 node = bmheads[1]
266 node = bmheads[1]
267 else:
267 else:
268 node = bmheads[0]
268 node = bmheads[0]
269 elif len(bmheads) > 2:
269 elif len(bmheads) > 2:
270 msg, hint = msgdestmerge['toomanybookmarks'][action]
270 msg, hint = msgdestmerge['toomanybookmarks'][action]
271 raise error.ManyMergeDestAbort(msg, hint=hint)
271 raise error.ManyMergeDestAbort(msg, hint=hint)
272 elif len(bmheads) <= 1:
272 elif len(bmheads) <= 1:
273 msg, hint = msgdestmerge['nootherbookmarks'][action]
273 msg, hint = msgdestmerge['nootherbookmarks'][action]
274 raise error.NoMergeDestAbort(msg, hint=hint)
274 raise error.NoMergeDestAbort(msg, hint=hint)
275 assert node is not None
275 assert node is not None
276 return node
276 return node
277
277
278 def _destmergebranch(repo, action='merge', sourceset=None, onheadcheck=True):
278 def _destmergebranch(repo, action='merge', sourceset=None, onheadcheck=True):
279 """find merge destination based on branch heads"""
279 """find merge destination based on branch heads"""
280 node = None
280 node = None
281
281
282 if sourceset is None:
282 if sourceset is None:
283 sourceset = [repo[repo.dirstate.p1()].rev()]
283 sourceset = [repo[repo.dirstate.p1()].rev()]
284 branch = repo.dirstate.branch()
284 branch = repo.dirstate.branch()
285 elif not sourceset:
285 elif not sourceset:
286 msg, hint = msgdestmerge['emptysourceset'][action]
286 msg, hint = msgdestmerge['emptysourceset'][action]
287 raise error.NoMergeDestAbort(msg, hint=hint)
287 raise error.NoMergeDestAbort(msg, hint=hint)
288 else:
288 else:
289 branch = None
289 branch = None
290 for ctx in repo.set('roots(%ld::%ld)', sourceset, sourceset):
290 for ctx in repo.set('roots(%ld::%ld)', sourceset, sourceset):
291 if branch is not None and ctx.branch() != branch:
291 if branch is not None and ctx.branch() != branch:
292 msg, hint = msgdestmerge['multiplebranchessourceset'][action]
292 msg, hint = msgdestmerge['multiplebranchessourceset'][action]
293 raise error.ManyMergeDestAbort(msg, hint=hint)
293 raise error.ManyMergeDestAbort(msg, hint=hint)
294 branch = ctx.branch()
294 branch = ctx.branch()
295
295
296 bheads = repo.branchheads(branch)
296 bheads = repo.branchheads(branch)
297 onhead = repo.revs('%ld and %ln', sourceset, bheads)
297 onhead = repo.revs('%ld and %ln', sourceset, bheads)
298 if onheadcheck and not onhead:
298 if onheadcheck and not onhead:
299 # Case A: working copy if not on a head. (merge only)
299 # Case A: working copy if not on a head. (merge only)
300 #
300 #
301 # This is probably a user mistake We bailout pointing at 'hg update'
301 # This is probably a user mistake We bailout pointing at 'hg update'
302 if len(repo.heads()) <= 1:
302 if len(repo.heads()) <= 1:
303 msg, hint = msgdestmerge['nootherheadsbehind'][action]
303 msg, hint = msgdestmerge['nootherheadsbehind'][action]
304 else:
304 else:
305 msg, hint = msgdestmerge['notatheads'][action]
305 msg, hint = msgdestmerge['notatheads'][action]
306 raise error.Abort(msg, hint=hint)
306 raise error.Abort(msg, hint=hint)
307 # remove heads descendants of source from the set
307 # remove heads descendants of source from the set
308 bheads = list(repo.revs('%ln - (%ld::)', bheads, sourceset))
308 bheads = list(repo.revs('%ln - (%ld::)', bheads, sourceset))
309 # filters out bookmarked heads
309 # filters out bookmarked heads
310 nbhs = list(repo.revs('%ld - bookmark()', bheads))
310 nbhs = list(repo.revs('%ld - bookmark()', bheads))
311 if len(nbhs) > 1:
311 if len(nbhs) > 1:
312 # Case B: There is more than 1 other anonymous heads
312 # Case B: There is more than 1 other anonymous heads
313 #
313 #
314 # This means that there will be more than 1 candidate. This is
314 # This means that there will be more than 1 candidate. This is
315 # ambiguous. We abort asking the user to pick as explicit destination
315 # ambiguous. We abort asking the user to pick as explicit destination
316 # instead.
316 # instead.
317 msg, hint = msgdestmerge['toomanyheads'][action]
317 msg, hint = msgdestmerge['toomanyheads'][action]
318 msg %= (branch, len(bheads) + 1)
318 msg %= (branch, len(bheads) + 1)
319 raise error.ManyMergeDestAbort(msg, hint=hint)
319 raise error.ManyMergeDestAbort(msg, hint=hint)
320 elif not nbhs:
320 elif not nbhs:
321 # Case B: There is no other anonymous heads
321 # Case B: There is no other anonymous heads
322 #
322 #
323 # This means that there is no natural candidate to merge with.
323 # This means that there is no natural candidate to merge with.
324 # We abort, with various messages for various cases.
324 # We abort, with various messages for various cases.
325 if bheads:
325 if bheads:
326 msg, hint = msgdestmerge['bookmarkedheads'][action]
326 msg, hint = msgdestmerge['bookmarkedheads'][action]
327 elif len(repo.heads()) > 1:
327 elif len(repo.heads()) > 1:
328 msg, hint = msgdestmerge['nootherbranchheads'][action]
328 msg, hint = msgdestmerge['nootherbranchheads'][action]
329 msg %= branch
329 msg %= branch
330 elif not onhead:
330 elif not onhead:
331 # if 'onheadcheck == False' (rebase case),
331 # if 'onheadcheck == False' (rebase case),
332 # this was not caught in Case A.
332 # this was not caught in Case A.
333 msg, hint = msgdestmerge['nootherheadsbehind'][action]
333 msg, hint = msgdestmerge['nootherheadsbehind'][action]
334 else:
334 else:
335 msg, hint = msgdestmerge['nootherheads'][action]
335 msg, hint = msgdestmerge['nootherheads'][action]
336 raise error.NoMergeDestAbort(msg, hint=hint)
336 raise error.NoMergeDestAbort(msg, hint=hint)
337 else:
337 else:
338 node = nbhs[0]
338 node = nbhs[0]
339 assert node is not None
339 assert node is not None
340 return node
340 return node
341
341
342 def destmerge(repo, action='merge', sourceset=None, onheadcheck=True):
342 def destmerge(repo, action='merge', sourceset=None, onheadcheck=True):
343 """return the default destination for a merge
343 """return the default destination for a merge
344
344
345 (or raise exception about why it can't pick one)
345 (or raise exception about why it can't pick one)
346
346
347 :action: the action being performed, controls emitted error message
347 :action: the action being performed, controls emitted error message
348 """
348 """
349 if repo._activebookmark:
349 if repo._activebookmark:
350 node = _destmergebook(repo, action=action, sourceset=sourceset)
350 node = _destmergebook(repo, action=action, sourceset=sourceset)
351 else:
351 else:
352 node = _destmergebranch(repo, action=action, sourceset=sourceset,
352 node = _destmergebranch(repo, action=action, sourceset=sourceset,
353 onheadcheck=onheadcheck)
353 onheadcheck=onheadcheck)
354 return repo[node].rev()
354 return repo[node].rev()
355
355
356 histeditdefaultrevset = 'reverse(only(.) and not public() and not ::merge())'
356 histeditdefaultrevset = 'reverse(only(.) and not public() and not ::merge())'
357
357
358 def desthistedit(ui, repo):
358 def desthistedit(ui, repo):
359 """Default base revision to edit for `hg histedit`."""
359 """Default base revision to edit for `hg histedit`."""
360 # Avoid cycle: scmutil -> revset -> destutil
360 # Avoid cycle: scmutil -> revset -> destutil
361 from . import scmutil
361 from . import scmutil
362
362
363 default = ui.config('histedit', 'defaultrev', histeditdefaultrevset)
363 default = ui.config('histedit', 'defaultrev', histeditdefaultrevset)
364 if default:
364 if default:
365 revs = scmutil.revrange(repo, [default])
365 revs = scmutil.revrange(repo, [default])
366 if revs:
366 if revs:
367 # The revset supplied by the user may not be in ascending order nor
367 # The revset supplied by the user may not be in ascending order nor
368 # take the first revision. So do this manually.
368 # take the first revision. So do this manually.
369 revs.sort()
369 revs.sort()
370 return revs.first()
370 return revs.first()
371
371
372 return None
372 return None
373
373
374 def _statusotherbook(ui, repo):
374 def _statusotherbook(ui, repo):
375 bmheads = repo.bookmarkheads(repo._activebookmark)
375 bmheads = repo.bookmarkheads(repo._activebookmark)
376 curhead = repo[repo._activebookmark].node()
376 curhead = repo[repo._activebookmark].node()
377 if repo.revs('%n and parents()', curhead):
377 if repo.revs('%n and parents()', curhead):
378 # we are on the active bookmark
378 # we are on the active bookmark
379 bmheads = [b for b in bmheads if curhead != b]
379 bmheads = [b for b in bmheads if curhead != b]
380 if bmheads:
380 if bmheads:
381 msg = _('%i other divergent bookmarks for "%s"\n')
381 msg = _('%i other divergent bookmarks for "%s"\n')
382 ui.status(msg % (len(bmheads), repo._activebookmark))
382 ui.status(msg % (len(bmheads), repo._activebookmark))
383
383
384 def _statusotherbranchheads(ui, repo):
384 def _statusotherbranchheads(ui, repo):
385 currentbranch = repo.dirstate.branch()
385 currentbranch = repo.dirstate.branch()
386 allheads = repo.branchheads(currentbranch, closed=True)
386 allheads = repo.branchheads(currentbranch, closed=True)
387 heads = repo.branchheads(currentbranch)
387 heads = repo.branchheads(currentbranch)
388 if repo.revs('%ln and parents()', allheads):
388 if repo.revs('%ln and parents()', allheads):
389 # we are on a head, even though it might be closed
389 # we are on a head, even though it might be closed
390 #
390 #
391 # on closed otherheads
391 # on closed otherheads
392 # ========= ==========
392 # ========= ==========
393 # o 0 all heads for current branch are closed
393 # o 0 all heads for current branch are closed
394 # N only descendant branch heads are closed
394 # N only descendant branch heads are closed
395 # x 0 there is only one non-closed branch head
395 # x 0 there is only one non-closed branch head
396 # N there are some non-closed branch heads
396 # N there are some non-closed branch heads
397 # ========= ==========
397 # ========= ==========
398 otherheads = repo.revs('%ln - parents()', heads)
398 otherheads = repo.revs('%ln - parents()', heads)
399 if repo['.'].closesbranch():
399 if repo['.'].closesbranch():
400 ui.status(_('updated to a closed branch head, '
400 ui.status(_('no open descendant heads on branch "%s", '
401 'because all descendant heads are closed.\n'
401 'updating to a closed head\n') %
402 'beware of re-opening closed head '
402 (currentbranch))
403 'by subsequent commit here.\n'))
404 if otherheads:
403 if otherheads:
405 ui.status(_('%i other heads for branch "%s"\n') %
404 ui.status(_('(committing will reopen the head, '
406 (len(otherheads), currentbranch))
405 'use `hg heads .` to see %i other heads)\n') %
406 (len(otherheads)))
407 else:
407 else:
408 ui.status(_('all heads for branch "%s" are closed.\n') %
408 ui.status(_('(committing will reopen branch "%s")\n') %
409 currentbranch)
409 (currentbranch))
410 elif otherheads:
410 elif otherheads:
411 ui.status(_('%i other heads for branch "%s"\n') %
411 ui.status(_('%i other heads for branch "%s"\n') %
412 (len(otherheads), currentbranch))
412 (len(otherheads), currentbranch))
413
413
414 def statusotherdests(ui, repo):
414 def statusotherdests(ui, repo):
415 """Print message about other head"""
415 """Print message about other head"""
416 # XXX we should probably include a hint:
416 # XXX we should probably include a hint:
417 # - about what to do
417 # - about what to do
418 # - how to see such heads
418 # - how to see such heads
419 if repo._activebookmark:
419 if repo._activebookmark:
420 _statusotherbook(ui, repo)
420 _statusotherbook(ui, repo)
421 else:
421 else:
422 _statusotherbranchheads(ui, repo)
422 _statusotherbranchheads(ui, repo)
@@ -1,400 +1,399 b''
1 #require mtn
1 #require mtn
2
2
3 Monotone directory is called .monotone on *nix and monotone
3 Monotone directory is called .monotone on *nix and monotone
4 on Windows.
4 on Windows.
5
5
6 #if windows
6 #if windows
7
7
8 $ mtndir=monotone
8 $ mtndir=monotone
9
9
10 #else
10 #else
11
11
12 $ mtndir=.monotone
12 $ mtndir=.monotone
13
13
14 #endif
14 #endif
15
15
16 $ echo "[extensions]" >> $HGRCPATH
16 $ echo "[extensions]" >> $HGRCPATH
17 $ echo "convert=" >> $HGRCPATH
17 $ echo "convert=" >> $HGRCPATH
18
18
19 Windows version of monotone home
19 Windows version of monotone home
20
20
21 $ APPDATA=$HOME; export APPDATA
21 $ APPDATA=$HOME; export APPDATA
22
22
23 tedious monotone keys configuration
23 tedious monotone keys configuration
24 The /dev/null redirection is necessary under Windows, or
24 The /dev/null redirection is necessary under Windows, or
25 it complains about home directory permissions
25 it complains about home directory permissions
26
26
27 $ mtn --quiet genkey test@selenic.com 1>/dev/null 2>&1 <<EOF
27 $ mtn --quiet genkey test@selenic.com 1>/dev/null 2>&1 <<EOF
28 > passphrase
28 > passphrase
29 > passphrase
29 > passphrase
30 > EOF
30 > EOF
31 $ cat >> $HOME/$mtndir/monotonerc <<EOF
31 $ cat >> $HOME/$mtndir/monotonerc <<EOF
32 > function get_passphrase(keypair_id)
32 > function get_passphrase(keypair_id)
33 > return "passphrase"
33 > return "passphrase"
34 > end
34 > end
35 > EOF
35 > EOF
36
36
37 create monotone repository
37 create monotone repository
38
38
39 $ mtn db init --db=repo.mtn
39 $ mtn db init --db=repo.mtn
40 $ mtn --db=repo.mtn --branch=com.selenic.test setup workingdir
40 $ mtn --db=repo.mtn --branch=com.selenic.test setup workingdir
41 $ cd workingdir
41 $ cd workingdir
42 $ echo a > a
42 $ echo a > a
43 $ mkdir dir
43 $ mkdir dir
44 $ echo b > dir/b
44 $ echo b > dir/b
45 $ echo d > dir/d
45 $ echo d > dir/d
46 $ $PYTHON -c 'file("bin", "wb").write("a\\x00b")'
46 $ $PYTHON -c 'file("bin", "wb").write("a\\x00b")'
47 $ echo c > c
47 $ echo c > c
48 $ mtn add a dir/b dir/d c bin
48 $ mtn add a dir/b dir/d c bin
49 mtn: adding 'a' to workspace manifest
49 mtn: adding 'a' to workspace manifest
50 mtn: adding 'bin' to workspace manifest
50 mtn: adding 'bin' to workspace manifest
51 mtn: adding 'c' to workspace manifest
51 mtn: adding 'c' to workspace manifest
52 mtn: adding 'dir' to workspace manifest
52 mtn: adding 'dir' to workspace manifest
53 mtn: adding 'dir/b' to workspace manifest
53 mtn: adding 'dir/b' to workspace manifest
54 mtn: adding 'dir/d' to workspace manifest
54 mtn: adding 'dir/d' to workspace manifest
55 $ mtn ci -m initialize
55 $ mtn ci -m initialize
56 mtn: beginning commit on branch 'com.selenic.test'
56 mtn: beginning commit on branch 'com.selenic.test'
57 mtn: committed revision 0f6e5e4f2e7d2a8ef312408f57618abf026afd90
57 mtn: committed revision 0f6e5e4f2e7d2a8ef312408f57618abf026afd90
58
58
59 update monotone working directory
59 update monotone working directory
60
60
61 $ mtn mv a dir/a
61 $ mtn mv a dir/a
62 mtn: skipping 'dir', already accounted for in workspace
62 mtn: skipping 'dir', already accounted for in workspace
63 mtn: renaming 'a' to 'dir/a' in workspace manifest
63 mtn: renaming 'a' to 'dir/a' in workspace manifest
64 $ echo a >> dir/a
64 $ echo a >> dir/a
65 $ echo b >> dir/b
65 $ echo b >> dir/b
66 $ mtn drop c
66 $ mtn drop c
67 mtn: dropping 'c' from workspace manifest
67 mtn: dropping 'c' from workspace manifest
68 $ $PYTHON -c 'file("bin", "wb").write("b\\x00c")'
68 $ $PYTHON -c 'file("bin", "wb").write("b\\x00c")'
69 $ mtn ci -m update1
69 $ mtn ci -m update1
70 mtn: beginning commit on branch 'com.selenic.test'
70 mtn: beginning commit on branch 'com.selenic.test'
71 mtn: committed revision 51d0a982464573a2a2cf5ee2c9219c652aaebeff
71 mtn: committed revision 51d0a982464573a2a2cf5ee2c9219c652aaebeff
72 $ cd ..
72 $ cd ..
73
73
74 convert once
74 convert once
75
75
76 $ hg convert -s mtn repo.mtn
76 $ hg convert -s mtn repo.mtn
77 assuming destination repo.mtn-hg
77 assuming destination repo.mtn-hg
78 initializing destination repo.mtn-hg repository
78 initializing destination repo.mtn-hg repository
79 scanning source...
79 scanning source...
80 sorting...
80 sorting...
81 converting...
81 converting...
82 1 initialize
82 1 initialize
83 0 update1
83 0 update1
84 $ cd workingdir
84 $ cd workingdir
85 $ echo e > e
85 $ echo e > e
86 $ mtn add e
86 $ mtn add e
87 mtn: adding 'e' to workspace manifest
87 mtn: adding 'e' to workspace manifest
88 $ mtn drop dir/b
88 $ mtn drop dir/b
89 mtn: dropping 'dir/b' from workspace manifest
89 mtn: dropping 'dir/b' from workspace manifest
90 $ mtn mv bin bin2
90 $ mtn mv bin bin2
91 mtn: renaming 'bin' to 'bin2' in workspace manifest
91 mtn: renaming 'bin' to 'bin2' in workspace manifest
92 $ mtn ci -m 'update2 "with" quotes'
92 $ mtn ci -m 'update2 "with" quotes'
93 mtn: beginning commit on branch 'com.selenic.test'
93 mtn: beginning commit on branch 'com.selenic.test'
94 mtn: committed revision ebe58335d85d8cb176b6d0a12be04f5314b998da
94 mtn: committed revision ebe58335d85d8cb176b6d0a12be04f5314b998da
95
95
96 test directory move
96 test directory move
97
97
98 $ mkdir -p dir1/subdir1
98 $ mkdir -p dir1/subdir1
99 $ mkdir -p dir1/subdir2_other
99 $ mkdir -p dir1/subdir2_other
100 $ echo file1 > dir1/subdir1/file1
100 $ echo file1 > dir1/subdir1/file1
101 $ echo file2 > dir1/subdir2_other/file1
101 $ echo file2 > dir1/subdir2_other/file1
102 $ mtn add dir1/subdir1/file1 dir1/subdir2_other/file1
102 $ mtn add dir1/subdir1/file1 dir1/subdir2_other/file1
103 mtn: adding 'dir1' to workspace manifest
103 mtn: adding 'dir1' to workspace manifest
104 mtn: adding 'dir1/subdir1' to workspace manifest
104 mtn: adding 'dir1/subdir1' to workspace manifest
105 mtn: adding 'dir1/subdir1/file1' to workspace manifest
105 mtn: adding 'dir1/subdir1/file1' to workspace manifest
106 mtn: adding 'dir1/subdir2_other' to workspace manifest
106 mtn: adding 'dir1/subdir2_other' to workspace manifest
107 mtn: adding 'dir1/subdir2_other/file1' to workspace manifest
107 mtn: adding 'dir1/subdir2_other/file1' to workspace manifest
108 $ mtn ci -m createdir1
108 $ mtn ci -m createdir1
109 mtn: beginning commit on branch 'com.selenic.test'
109 mtn: beginning commit on branch 'com.selenic.test'
110 mtn: committed revision a8d62bc04fee4d2936d28e98bbcc81686dd74306
110 mtn: committed revision a8d62bc04fee4d2936d28e98bbcc81686dd74306
111 $ mtn rename dir1/subdir1 dir1/subdir2
111 $ mtn rename dir1/subdir1 dir1/subdir2
112 mtn: skipping 'dir1', already accounted for in workspace
112 mtn: skipping 'dir1', already accounted for in workspace
113 mtn: renaming 'dir1/subdir1' to 'dir1/subdir2' in workspace manifest
113 mtn: renaming 'dir1/subdir1' to 'dir1/subdir2' in workspace manifest
114 $ mtn ci -m movedir1
114 $ mtn ci -m movedir1
115 mtn: beginning commit on branch 'com.selenic.test'
115 mtn: beginning commit on branch 'com.selenic.test'
116 mtn: committed revision 2c3d241bbbfe538b1b51d910f5676407e3f4d3a6
116 mtn: committed revision 2c3d241bbbfe538b1b51d910f5676407e3f4d3a6
117
117
118 test subdirectory move
118 test subdirectory move
119
119
120 $ mtn mv dir dir2
120 $ mtn mv dir dir2
121 mtn: renaming 'dir' to 'dir2' in workspace manifest
121 mtn: renaming 'dir' to 'dir2' in workspace manifest
122 $ echo newfile > dir2/newfile
122 $ echo newfile > dir2/newfile
123 $ mtn drop dir2/d
123 $ mtn drop dir2/d
124 mtn: dropping 'dir2/d' from workspace manifest
124 mtn: dropping 'dir2/d' from workspace manifest
125 $ mtn add dir2/newfile
125 $ mtn add dir2/newfile
126 mtn: adding 'dir2/newfile' to workspace manifest
126 mtn: adding 'dir2/newfile' to workspace manifest
127 $ mtn ci -m movedir
127 $ mtn ci -m movedir
128 mtn: beginning commit on branch 'com.selenic.test'
128 mtn: beginning commit on branch 'com.selenic.test'
129 mtn: committed revision fdb5a02dae8bfce3a79b3393680af471016e1b4c
129 mtn: committed revision fdb5a02dae8bfce3a79b3393680af471016e1b4c
130
130
131 Test directory removal with empty directory
131 Test directory removal with empty directory
132
132
133 $ mkdir dir2/dir
133 $ mkdir dir2/dir
134 $ mkdir dir2/dir/subdir
134 $ mkdir dir2/dir/subdir
135 $ echo f > dir2/dir/subdir/f
135 $ echo f > dir2/dir/subdir/f
136 $ mkdir dir2/dir/emptydir
136 $ mkdir dir2/dir/emptydir
137 $ mtn add --quiet -R dir2/dir
137 $ mtn add --quiet -R dir2/dir
138 $ mtn ci -m emptydir
138 $ mtn ci -m emptydir
139 mtn: beginning commit on branch 'com.selenic.test'
139 mtn: beginning commit on branch 'com.selenic.test'
140 mtn: committed revision 8bbf76d717001d24964e4604739fdcd0f539fc88
140 mtn: committed revision 8bbf76d717001d24964e4604739fdcd0f539fc88
141 $ mtn drop -R dir2/dir
141 $ mtn drop -R dir2/dir
142 mtn: dropping 'dir2/dir/subdir/f' from workspace manifest
142 mtn: dropping 'dir2/dir/subdir/f' from workspace manifest
143 mtn: dropping 'dir2/dir/subdir' from workspace manifest
143 mtn: dropping 'dir2/dir/subdir' from workspace manifest
144 mtn: dropping 'dir2/dir/emptydir' from workspace manifest
144 mtn: dropping 'dir2/dir/emptydir' from workspace manifest
145 mtn: dropping 'dir2/dir' from workspace manifest
145 mtn: dropping 'dir2/dir' from workspace manifest
146 $ mtn ci -m dropdirectory
146 $ mtn ci -m dropdirectory
147 mtn: beginning commit on branch 'com.selenic.test'
147 mtn: beginning commit on branch 'com.selenic.test'
148 mtn: committed revision 2323d4bc324e6c82628dc04d47a9fd32ad24e322
148 mtn: committed revision 2323d4bc324e6c82628dc04d47a9fd32ad24e322
149
149
150 test directory and file move
150 test directory and file move
151
151
152 $ mkdir -p dir3/d1
152 $ mkdir -p dir3/d1
153 $ echo a > dir3/a
153 $ echo a > dir3/a
154 $ mtn add dir3/a dir3/d1
154 $ mtn add dir3/a dir3/d1
155 mtn: adding 'dir3' to workspace manifest
155 mtn: adding 'dir3' to workspace manifest
156 mtn: adding 'dir3/a' to workspace manifest
156 mtn: adding 'dir3/a' to workspace manifest
157 mtn: adding 'dir3/d1' to workspace manifest
157 mtn: adding 'dir3/d1' to workspace manifest
158 $ mtn ci -m dirfilemove
158 $ mtn ci -m dirfilemove
159 mtn: beginning commit on branch 'com.selenic.test'
159 mtn: beginning commit on branch 'com.selenic.test'
160 mtn: committed revision 47b192f720faa622f48c68d1eb075b26d405aa8b
160 mtn: committed revision 47b192f720faa622f48c68d1eb075b26d405aa8b
161 $ mtn mv dir3/a dir3/d1/a
161 $ mtn mv dir3/a dir3/d1/a
162 mtn: skipping 'dir3/d1', already accounted for in workspace
162 mtn: skipping 'dir3/d1', already accounted for in workspace
163 mtn: renaming 'dir3/a' to 'dir3/d1/a' in workspace manifest
163 mtn: renaming 'dir3/a' to 'dir3/d1/a' in workspace manifest
164 $ mtn mv dir3/d1 dir3/d2
164 $ mtn mv dir3/d1 dir3/d2
165 mtn: skipping 'dir3', already accounted for in workspace
165 mtn: skipping 'dir3', already accounted for in workspace
166 mtn: renaming 'dir3/d1' to 'dir3/d2' in workspace manifest
166 mtn: renaming 'dir3/d1' to 'dir3/d2' in workspace manifest
167 $ mtn ci -m dirfilemove2
167 $ mtn ci -m dirfilemove2
168 mtn: beginning commit on branch 'com.selenic.test'
168 mtn: beginning commit on branch 'com.selenic.test'
169 mtn: committed revision 8b543a400d3ee7f6d4bb1835b9b9e3747c8cb632
169 mtn: committed revision 8b543a400d3ee7f6d4bb1835b9b9e3747c8cb632
170
170
171 test directory move into another directory move
171 test directory move into another directory move
172
172
173 $ mkdir dir4
173 $ mkdir dir4
174 $ mkdir dir5
174 $ mkdir dir5
175 $ echo a > dir4/a
175 $ echo a > dir4/a
176 $ mtn add dir4/a dir5
176 $ mtn add dir4/a dir5
177 mtn: adding 'dir4' to workspace manifest
177 mtn: adding 'dir4' to workspace manifest
178 mtn: adding 'dir4/a' to workspace manifest
178 mtn: adding 'dir4/a' to workspace manifest
179 mtn: adding 'dir5' to workspace manifest
179 mtn: adding 'dir5' to workspace manifest
180 $ mtn ci -m dirdirmove
180 $ mtn ci -m dirdirmove
181 mtn: beginning commit on branch 'com.selenic.test'
181 mtn: beginning commit on branch 'com.selenic.test'
182 mtn: committed revision 466e0b2afc7a55aa2b4ab2f57cb240bb6cd66fc7
182 mtn: committed revision 466e0b2afc7a55aa2b4ab2f57cb240bb6cd66fc7
183 $ mtn mv dir5 dir6
183 $ mtn mv dir5 dir6
184 mtn: renaming 'dir5' to 'dir6' in workspace manifest
184 mtn: renaming 'dir5' to 'dir6' in workspace manifest
185 $ mtn mv dir4 dir6/dir4
185 $ mtn mv dir4 dir6/dir4
186 mtn: skipping 'dir6', already accounted for in workspace
186 mtn: skipping 'dir6', already accounted for in workspace
187 mtn: renaming 'dir4' to 'dir6/dir4' in workspace manifest
187 mtn: renaming 'dir4' to 'dir6/dir4' in workspace manifest
188 $ mtn ci -m dirdirmove2
188 $ mtn ci -m dirdirmove2
189 mtn: beginning commit on branch 'com.selenic.test'
189 mtn: beginning commit on branch 'com.selenic.test'
190 mtn: committed revision 3d1f77ebad0c23a5d14911be3b670f990991b749
190 mtn: committed revision 3d1f77ebad0c23a5d14911be3b670f990991b749
191
191
192 test diverging directory moves
192 test diverging directory moves
193
193
194 $ mkdir -p dir7/dir9/dir8
194 $ mkdir -p dir7/dir9/dir8
195 $ echo a > dir7/dir9/dir8/a
195 $ echo a > dir7/dir9/dir8/a
196 $ echo b > dir7/dir9/b
196 $ echo b > dir7/dir9/b
197 $ echo c > dir7/c
197 $ echo c > dir7/c
198 $ mtn add -R dir7
198 $ mtn add -R dir7
199 mtn: adding 'dir7' to workspace manifest
199 mtn: adding 'dir7' to workspace manifest
200 mtn: adding 'dir7/c' to workspace manifest
200 mtn: adding 'dir7/c' to workspace manifest
201 mtn: adding 'dir7/dir9' to workspace manifest
201 mtn: adding 'dir7/dir9' to workspace manifest
202 mtn: adding 'dir7/dir9/b' to workspace manifest
202 mtn: adding 'dir7/dir9/b' to workspace manifest
203 mtn: adding 'dir7/dir9/dir8' to workspace manifest
203 mtn: adding 'dir7/dir9/dir8' to workspace manifest
204 mtn: adding 'dir7/dir9/dir8/a' to workspace manifest
204 mtn: adding 'dir7/dir9/dir8/a' to workspace manifest
205 $ mtn ci -m divergentdirmove
205 $ mtn ci -m divergentdirmove
206 mtn: beginning commit on branch 'com.selenic.test'
206 mtn: beginning commit on branch 'com.selenic.test'
207 mtn: committed revision 08a08511f18b428d840199b062de90d0396bc2ed
207 mtn: committed revision 08a08511f18b428d840199b062de90d0396bc2ed
208 $ mtn mv dir7 dir7-2
208 $ mtn mv dir7 dir7-2
209 mtn: renaming 'dir7' to 'dir7-2' in workspace manifest
209 mtn: renaming 'dir7' to 'dir7-2' in workspace manifest
210 $ mtn mv dir7-2/dir9 dir9-2
210 $ mtn mv dir7-2/dir9 dir9-2
211 mtn: renaming 'dir7-2/dir9' to 'dir9-2' in workspace manifest
211 mtn: renaming 'dir7-2/dir9' to 'dir9-2' in workspace manifest
212 $ mtn mv dir9-2/dir8 dir8-2
212 $ mtn mv dir9-2/dir8 dir8-2
213 mtn: renaming 'dir9-2/dir8' to 'dir8-2' in workspace manifest
213 mtn: renaming 'dir9-2/dir8' to 'dir8-2' in workspace manifest
214 $ mtn ci -m divergentdirmove2
214 $ mtn ci -m divergentdirmove2
215 mtn: beginning commit on branch 'com.selenic.test'
215 mtn: beginning commit on branch 'com.selenic.test'
216 mtn: committed revision 4a736634505795f17786fffdf2c9cbf5b11df6f6
216 mtn: committed revision 4a736634505795f17786fffdf2c9cbf5b11df6f6
217
217
218 test large file support (> 32kB)
218 test large file support (> 32kB)
219
219
220 >>> fp = file('large-file', 'wb')
220 >>> fp = file('large-file', 'wb')
221 >>> for x in xrange(10000): fp.write('%d\n' % x)
221 >>> for x in xrange(10000): fp.write('%d\n' % x)
222 >>> fp.close()
222 >>> fp.close()
223 $ md5sum.py large-file
223 $ md5sum.py large-file
224 5d6de8a95c3b6bf9e0ffb808ba5299c1 large-file
224 5d6de8a95c3b6bf9e0ffb808ba5299c1 large-file
225 $ mtn add large-file
225 $ mtn add large-file
226 mtn: adding 'large-file' to workspace manifest
226 mtn: adding 'large-file' to workspace manifest
227 $ mtn ci -m largefile
227 $ mtn ci -m largefile
228 mtn: beginning commit on branch 'com.selenic.test'
228 mtn: beginning commit on branch 'com.selenic.test'
229 mtn: committed revision f0a20fecd10dc4392d18fe69a03f1f4919d3387b
229 mtn: committed revision f0a20fecd10dc4392d18fe69a03f1f4919d3387b
230
230
231 test suspending (closing a branch)
231 test suspending (closing a branch)
232
232
233 $ mtn suspend f0a20fecd10dc4392d18fe69a03f1f4919d3387b 2> /dev/null
233 $ mtn suspend f0a20fecd10dc4392d18fe69a03f1f4919d3387b 2> /dev/null
234 $ cd ..
234 $ cd ..
235
235
236 convert incrementally
236 convert incrementally
237
237
238 $ hg convert -s mtn repo.mtn
238 $ hg convert -s mtn repo.mtn
239 assuming destination repo.mtn-hg
239 assuming destination repo.mtn-hg
240 scanning source...
240 scanning source...
241 sorting...
241 sorting...
242 converting...
242 converting...
243 12 update2 "with" quotes
243 12 update2 "with" quotes
244 11 createdir1
244 11 createdir1
245 10 movedir1
245 10 movedir1
246 9 movedir
246 9 movedir
247 8 emptydir
247 8 emptydir
248 7 dropdirectory
248 7 dropdirectory
249 6 dirfilemove
249 6 dirfilemove
250 5 dirfilemove2
250 5 dirfilemove2
251 4 dirdirmove
251 4 dirdirmove
252 3 dirdirmove2
252 3 dirdirmove2
253 2 divergentdirmove
253 2 divergentdirmove
254 1 divergentdirmove2
254 1 divergentdirmove2
255 0 largefile
255 0 largefile
256 $ glog()
256 $ glog()
257 > {
257 > {
258 > hg log -G --template '{rev} "{desc|firstline}" files: {files}\n' "$@"
258 > hg log -G --template '{rev} "{desc|firstline}" files: {files}\n' "$@"
259 > }
259 > }
260 $ cd repo.mtn-hg
260 $ cd repo.mtn-hg
261 $ hg up -C
261 $ hg up -C
262 12 files updated, 0 files merged, 0 files removed, 0 files unresolved
262 12 files updated, 0 files merged, 0 files removed, 0 files unresolved
263 updated to a closed branch head, because all descendant heads are closed.
263 no open descendant heads on branch "com.selenic.test", updating to a closed head
264 beware of re-opening closed head by subsequent commit here.
264 (committing will reopen branch "com.selenic.test")
265 all heads for branch "com.selenic.test" are closed.
266 $ glog
265 $ glog
267 @ 14 "largefile" files: large-file
266 @ 14 "largefile" files: large-file
268 |
267 |
269 o 13 "divergentdirmove2" files: dir7-2/c dir7/c dir7/dir9/b dir7/dir9/dir8/a dir8-2/a dir9-2/b
268 o 13 "divergentdirmove2" files: dir7-2/c dir7/c dir7/dir9/b dir7/dir9/dir8/a dir8-2/a dir9-2/b
270 |
269 |
271 o 12 "divergentdirmove" files: dir7/c dir7/dir9/b dir7/dir9/dir8/a
270 o 12 "divergentdirmove" files: dir7/c dir7/dir9/b dir7/dir9/dir8/a
272 |
271 |
273 o 11 "dirdirmove2" files: dir4/a dir6/dir4/a
272 o 11 "dirdirmove2" files: dir4/a dir6/dir4/a
274 |
273 |
275 o 10 "dirdirmove" files: dir4/a
274 o 10 "dirdirmove" files: dir4/a
276 |
275 |
277 o 9 "dirfilemove2" files: dir3/a dir3/d2/a
276 o 9 "dirfilemove2" files: dir3/a dir3/d2/a
278 |
277 |
279 o 8 "dirfilemove" files: dir3/a
278 o 8 "dirfilemove" files: dir3/a
280 |
279 |
281 o 7 "dropdirectory" files: dir2/dir/subdir/f
280 o 7 "dropdirectory" files: dir2/dir/subdir/f
282 |
281 |
283 o 6 "emptydir" files: dir2/dir/subdir/f
282 o 6 "emptydir" files: dir2/dir/subdir/f
284 |
283 |
285 o 5 "movedir" files: dir/a dir/d dir2/a dir2/newfile
284 o 5 "movedir" files: dir/a dir/d dir2/a dir2/newfile
286 |
285 |
287 o 4 "movedir1" files: dir1/subdir1/file1 dir1/subdir2/file1
286 o 4 "movedir1" files: dir1/subdir1/file1 dir1/subdir2/file1
288 |
287 |
289 o 3 "createdir1" files: dir1/subdir1/file1 dir1/subdir2_other/file1
288 o 3 "createdir1" files: dir1/subdir1/file1 dir1/subdir2_other/file1
290 |
289 |
291 o 2 "update2 "with" quotes" files: bin bin2 dir/b e
290 o 2 "update2 "with" quotes" files: bin bin2 dir/b e
292 |
291 |
293 o 1 "update1" files: a bin c dir/a dir/b
292 o 1 "update1" files: a bin c dir/a dir/b
294 |
293 |
295 o 0 "initialize" files: a bin c dir/b dir/d
294 o 0 "initialize" files: a bin c dir/b dir/d
296
295
297
296
298 manifest
297 manifest
299
298
300 $ hg manifest
299 $ hg manifest
301 bin2
300 bin2
302 dir1/subdir2/file1
301 dir1/subdir2/file1
303 dir1/subdir2_other/file1
302 dir1/subdir2_other/file1
304 dir2/a
303 dir2/a
305 dir2/newfile
304 dir2/newfile
306 dir3/d2/a
305 dir3/d2/a
307 dir6/dir4/a
306 dir6/dir4/a
308 dir7-2/c
307 dir7-2/c
309 dir8-2/a
308 dir8-2/a
310 dir9-2/b
309 dir9-2/b
311 e
310 e
312 large-file
311 large-file
313
312
314 contents
313 contents
315
314
316 $ cat dir2/a
315 $ cat dir2/a
317 a
316 a
318 a
317 a
319 $ test -d dir2/dir && echo 'removed dir2/dir is still there!'
318 $ test -d dir2/dir && echo 'removed dir2/dir is still there!'
320 [1]
319 [1]
321
320
322 file move
321 file move
323
322
324 $ hg log -v -C -r 1 | grep copies
323 $ hg log -v -C -r 1 | grep copies
325 copies: dir/a (a)
324 copies: dir/a (a)
326
325
327 check directory move
326 check directory move
328
327
329 $ hg manifest -r 4
328 $ hg manifest -r 4
330 bin2
329 bin2
331 dir/a
330 dir/a
332 dir/d
331 dir/d
333 dir1/subdir2/file1
332 dir1/subdir2/file1
334 dir1/subdir2_other/file1
333 dir1/subdir2_other/file1
335 e
334 e
336 $ test -d dir1/subdir2 || echo 'new dir1/subdir2 does not exist!'
335 $ test -d dir1/subdir2 || echo 'new dir1/subdir2 does not exist!'
337 $ test -d dir1/subdir1 && echo 'renamed dir1/subdir1 is still there!'
336 $ test -d dir1/subdir1 && echo 'renamed dir1/subdir1 is still there!'
338 [1]
337 [1]
339 $ hg log -v -C -r 4 | grep copies
338 $ hg log -v -C -r 4 | grep copies
340 copies: dir1/subdir2/file1 (dir1/subdir1/file1)
339 copies: dir1/subdir2/file1 (dir1/subdir1/file1)
341
340
342 check file remove with directory move
341 check file remove with directory move
343
342
344 $ hg manifest -r 5
343 $ hg manifest -r 5
345 bin2
344 bin2
346 dir1/subdir2/file1
345 dir1/subdir2/file1
347 dir1/subdir2_other/file1
346 dir1/subdir2_other/file1
348 dir2/a
347 dir2/a
349 dir2/newfile
348 dir2/newfile
350 e
349 e
351
350
352 check file move with directory move
351 check file move with directory move
353
352
354 $ hg manifest -r 9
353 $ hg manifest -r 9
355 bin2
354 bin2
356 dir1/subdir2/file1
355 dir1/subdir2/file1
357 dir1/subdir2_other/file1
356 dir1/subdir2_other/file1
358 dir2/a
357 dir2/a
359 dir2/newfile
358 dir2/newfile
360 dir3/d2/a
359 dir3/d2/a
361 e
360 e
362
361
363 check file directory directory move
362 check file directory directory move
364
363
365 $ hg manifest -r 11
364 $ hg manifest -r 11
366 bin2
365 bin2
367 dir1/subdir2/file1
366 dir1/subdir2/file1
368 dir1/subdir2_other/file1
367 dir1/subdir2_other/file1
369 dir2/a
368 dir2/a
370 dir2/newfile
369 dir2/newfile
371 dir3/d2/a
370 dir3/d2/a
372 dir6/dir4/a
371 dir6/dir4/a
373 e
372 e
374
373
375 check divergent directory moves
374 check divergent directory moves
376
375
377 $ hg manifest -r 13
376 $ hg manifest -r 13
378 bin2
377 bin2
379 dir1/subdir2/file1
378 dir1/subdir2/file1
380 dir1/subdir2_other/file1
379 dir1/subdir2_other/file1
381 dir2/a
380 dir2/a
382 dir2/newfile
381 dir2/newfile
383 dir3/d2/a
382 dir3/d2/a
384 dir6/dir4/a
383 dir6/dir4/a
385 dir7-2/c
384 dir7-2/c
386 dir8-2/a
385 dir8-2/a
387 dir9-2/b
386 dir9-2/b
388 e
387 e
389
388
390 test large file support (> 32kB)
389 test large file support (> 32kB)
391
390
392 $ md5sum.py large-file
391 $ md5sum.py large-file
393 5d6de8a95c3b6bf9e0ffb808ba5299c1 large-file
392 5d6de8a95c3b6bf9e0ffb808ba5299c1 large-file
394
393
395 check branch closing
394 check branch closing
396
395
397 $ hg branches -a
396 $ hg branches -a
398 $ hg branches -c
397 $ hg branches -c
399 com.selenic.test 14:* (closed) (glob)
398 com.selenic.test 14:* (closed) (glob)
400
399
@@ -1,386 +1,381 b''
1 # Construct the following history tree:
1 # Construct the following history tree:
2 #
2 #
3 # @ 5:e1bb631146ca b1
3 # @ 5:e1bb631146ca b1
4 # |
4 # |
5 # o 4:a4fdb3b883c4 0:b608b9236435 b1
5 # o 4:a4fdb3b883c4 0:b608b9236435 b1
6 # |
6 # |
7 # | o 3:4b57d2520816 1:44592833ba9f
7 # | o 3:4b57d2520816 1:44592833ba9f
8 # | |
8 # | |
9 # | | o 2:063f31070f65
9 # | | o 2:063f31070f65
10 # | |/
10 # | |/
11 # | o 1:44592833ba9f
11 # | o 1:44592833ba9f
12 # |/
12 # |/
13 # o 0:b608b9236435
13 # o 0:b608b9236435
14
14
15 $ mkdir b1
15 $ mkdir b1
16 $ cd b1
16 $ cd b1
17 $ hg init
17 $ hg init
18 $ echo foo > foo
18 $ echo foo > foo
19 $ echo zero > a
19 $ echo zero > a
20 $ hg init sub
20 $ hg init sub
21 $ echo suba > sub/suba
21 $ echo suba > sub/suba
22 $ hg --cwd sub ci -Am addsuba
22 $ hg --cwd sub ci -Am addsuba
23 adding suba
23 adding suba
24 $ echo 'sub = sub' > .hgsub
24 $ echo 'sub = sub' > .hgsub
25 $ hg ci -qAm0
25 $ hg ci -qAm0
26 $ echo one > a ; hg ci -m1
26 $ echo one > a ; hg ci -m1
27 $ echo two > a ; hg ci -m2
27 $ echo two > a ; hg ci -m2
28 $ hg up -q 1
28 $ hg up -q 1
29 $ echo three > a ; hg ci -qm3
29 $ echo three > a ; hg ci -qm3
30 $ hg up -q 0
30 $ hg up -q 0
31 $ hg branch -q b1
31 $ hg branch -q b1
32 $ echo four > a ; hg ci -qm4
32 $ echo four > a ; hg ci -qm4
33 $ echo five > a ; hg ci -qm5
33 $ echo five > a ; hg ci -qm5
34
34
35 Initial repo state:
35 Initial repo state:
36
36
37 $ hg log -G --template '{rev}:{node|short} {parents} {branches}\n'
37 $ hg log -G --template '{rev}:{node|short} {parents} {branches}\n'
38 @ 5:ff252e8273df b1
38 @ 5:ff252e8273df b1
39 |
39 |
40 o 4:d047485b3896 0:60829823a42a b1
40 o 4:d047485b3896 0:60829823a42a b1
41 |
41 |
42 | o 3:6efa171f091b 1:0786582aa4b1
42 | o 3:6efa171f091b 1:0786582aa4b1
43 | |
43 | |
44 | | o 2:bd10386d478c
44 | | o 2:bd10386d478c
45 | |/
45 | |/
46 | o 1:0786582aa4b1
46 | o 1:0786582aa4b1
47 |/
47 |/
48 o 0:60829823a42a
48 o 0:60829823a42a
49
49
50
50
51 Make sure update doesn't assume b1 is a repository if invoked from outside:
51 Make sure update doesn't assume b1 is a repository if invoked from outside:
52
52
53 $ cd ..
53 $ cd ..
54 $ hg update b1
54 $ hg update b1
55 abort: no repository found in '$TESTTMP' (.hg not found)!
55 abort: no repository found in '$TESTTMP' (.hg not found)!
56 [255]
56 [255]
57 $ cd b1
57 $ cd b1
58
58
59 Test helper functions:
59 Test helper functions:
60
60
61 $ revtest () {
61 $ revtest () {
62 > msg=$1
62 > msg=$1
63 > dirtyflag=$2 # 'clean', 'dirty' or 'dirtysub'
63 > dirtyflag=$2 # 'clean', 'dirty' or 'dirtysub'
64 > startrev=$3
64 > startrev=$3
65 > targetrev=$4
65 > targetrev=$4
66 > opt=$5
66 > opt=$5
67 > hg up -qC $startrev
67 > hg up -qC $startrev
68 > test $dirtyflag = dirty && echo dirty > foo
68 > test $dirtyflag = dirty && echo dirty > foo
69 > test $dirtyflag = dirtysub && echo dirty > sub/suba
69 > test $dirtyflag = dirtysub && echo dirty > sub/suba
70 > hg up $opt $targetrev
70 > hg up $opt $targetrev
71 > hg parent --template 'parent={rev}\n'
71 > hg parent --template 'parent={rev}\n'
72 > hg stat -S
72 > hg stat -S
73 > }
73 > }
74
74
75 $ norevtest () {
75 $ norevtest () {
76 > msg=$1
76 > msg=$1
77 > dirtyflag=$2 # 'clean', 'dirty' or 'dirtysub'
77 > dirtyflag=$2 # 'clean', 'dirty' or 'dirtysub'
78 > startrev=$3
78 > startrev=$3
79 > opt=$4
79 > opt=$4
80 > hg up -qC $startrev
80 > hg up -qC $startrev
81 > test $dirtyflag = dirty && echo dirty > foo
81 > test $dirtyflag = dirty && echo dirty > foo
82 > test $dirtyflag = dirtysub && echo dirty > sub/suba
82 > test $dirtyflag = dirtysub && echo dirty > sub/suba
83 > hg up $opt
83 > hg up $opt
84 > hg parent --template 'parent={rev}\n'
84 > hg parent --template 'parent={rev}\n'
85 > hg stat -S
85 > hg stat -S
86 > }
86 > }
87
87
88 Test cases are documented in a table in the update function of merge.py.
88 Test cases are documented in a table in the update function of merge.py.
89 Cases are run as shown in that table, row by row.
89 Cases are run as shown in that table, row by row.
90
90
91 $ norevtest 'none clean linear' clean 4
91 $ norevtest 'none clean linear' clean 4
92 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
92 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
93 parent=5
93 parent=5
94
94
95 $ norevtest 'none clean same' clean 2
95 $ norevtest 'none clean same' clean 2
96 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
96 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
97 1 other heads for branch "default"
97 1 other heads for branch "default"
98 parent=2
98 parent=2
99
99
100
100
101 $ revtest 'none clean linear' clean 1 2
101 $ revtest 'none clean linear' clean 1 2
102 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
102 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
103 parent=2
103 parent=2
104
104
105 $ revtest 'none clean same' clean 2 3
105 $ revtest 'none clean same' clean 2 3
106 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
106 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
107 parent=3
107 parent=3
108
108
109 $ revtest 'none clean cross' clean 3 4
109 $ revtest 'none clean cross' clean 3 4
110 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
110 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
111 parent=4
111 parent=4
112
112
113
113
114 $ revtest 'none dirty linear' dirty 1 2
114 $ revtest 'none dirty linear' dirty 1 2
115 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
115 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
116 parent=2
116 parent=2
117 M foo
117 M foo
118
118
119 $ revtest 'none dirtysub linear' dirtysub 1 2
119 $ revtest 'none dirtysub linear' dirtysub 1 2
120 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
120 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
121 parent=2
121 parent=2
122 M sub/suba
122 M sub/suba
123
123
124 $ revtest 'none dirty same' dirty 2 3
124 $ revtest 'none dirty same' dirty 2 3
125 abort: uncommitted changes
125 abort: uncommitted changes
126 (commit or update --clean to discard changes)
126 (commit or update --clean to discard changes)
127 parent=2
127 parent=2
128 M foo
128 M foo
129
129
130 $ revtest 'none dirtysub same' dirtysub 2 3
130 $ revtest 'none dirtysub same' dirtysub 2 3
131 abort: uncommitted changes
131 abort: uncommitted changes
132 (commit or update --clean to discard changes)
132 (commit or update --clean to discard changes)
133 parent=2
133 parent=2
134 M sub/suba
134 M sub/suba
135
135
136 $ revtest 'none dirty cross' dirty 3 4
136 $ revtest 'none dirty cross' dirty 3 4
137 abort: uncommitted changes
137 abort: uncommitted changes
138 (commit or update --clean to discard changes)
138 (commit or update --clean to discard changes)
139 parent=3
139 parent=3
140 M foo
140 M foo
141
141
142 $ norevtest 'none dirty cross' dirty 2
142 $ norevtest 'none dirty cross' dirty 2
143 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
143 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
144 1 other heads for branch "default"
144 1 other heads for branch "default"
145 parent=2
145 parent=2
146 M foo
146 M foo
147
147
148 $ revtest 'none dirtysub cross' dirtysub 3 4
148 $ revtest 'none dirtysub cross' dirtysub 3 4
149 abort: uncommitted changes
149 abort: uncommitted changes
150 (commit or update --clean to discard changes)
150 (commit or update --clean to discard changes)
151 parent=3
151 parent=3
152 M sub/suba
152 M sub/suba
153
153
154 $ revtest '-C dirty linear' dirty 1 2 -C
154 $ revtest '-C dirty linear' dirty 1 2 -C
155 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
155 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
156 parent=2
156 parent=2
157
157
158 $ revtest '-c dirty linear' dirty 1 2 -c
158 $ revtest '-c dirty linear' dirty 1 2 -c
159 abort: uncommitted changes
159 abort: uncommitted changes
160 parent=1
160 parent=1
161 M foo
161 M foo
162
162
163 $ revtest '-c dirtysub linear' dirtysub 1 2 -c
163 $ revtest '-c dirtysub linear' dirtysub 1 2 -c
164 abort: uncommitted changes in subrepository 'sub'
164 abort: uncommitted changes in subrepository 'sub'
165 parent=1
165 parent=1
166 M sub/suba
166 M sub/suba
167
167
168 $ norevtest '-c clean same' clean 2 -c
168 $ norevtest '-c clean same' clean 2 -c
169 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
169 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
170 1 other heads for branch "default"
170 1 other heads for branch "default"
171 parent=2
171 parent=2
172
172
173 $ revtest '-cC dirty linear' dirty 1 2 -cC
173 $ revtest '-cC dirty linear' dirty 1 2 -cC
174 abort: cannot specify both -c/--check and -C/--clean
174 abort: cannot specify both -c/--check and -C/--clean
175 parent=1
175 parent=1
176 M foo
176 M foo
177
177
178 $ cd ..
178 $ cd ..
179
179
180 Test updating with closed head
180 Test updating with closed head
181 ---------------------------------------------------------------------
181 ---------------------------------------------------------------------
182
182
183 $ hg clone -U -q b1 closed-heads
183 $ hg clone -U -q b1 closed-heads
184 $ cd closed-heads
184 $ cd closed-heads
185
185
186 Test updating if at least one non-closed branch head exists
186 Test updating if at least one non-closed branch head exists
187
187
188 if on the closed branch head:
188 if on the closed branch head:
189 - update to "."
189 - update to "."
190 - "updated to a closed branch head ...." message is displayed
190 - "updated to a closed branch head ...." message is displayed
191 - "N other heads for ...." message is displayed
191 - "N other heads for ...." message is displayed
192
192
193 $ hg update -q -C 3
193 $ hg update -q -C 3
194 $ hg commit --close-branch -m 6
194 $ hg commit --close-branch -m 6
195 $ norevtest "on closed branch head" clean 6
195 $ norevtest "on closed branch head" clean 6
196 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
196 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
197 updated to a closed branch head, because all descendant heads are closed.
197 no open descendant heads on branch "default", updating to a closed head
198 beware of re-opening closed head by subsequent commit here.
198 (committing will reopen the head, use `hg heads .` to see 1 other heads)
199 1 other heads for branch "default"
200 parent=6
199 parent=6
201
200
202 if descendant non-closed branch head exists, and it is only one branch head:
201 if descendant non-closed branch head exists, and it is only one branch head:
203 - update to it, even if its revision is less than closed one
202 - update to it, even if its revision is less than closed one
204 - "N other heads for ...." message isn't displayed
203 - "N other heads for ...." message isn't displayed
205
204
206 $ norevtest "non-closed 2 should be chosen" clean 1
205 $ norevtest "non-closed 2 should be chosen" clean 1
207 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
206 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
208 parent=2
207 parent=2
209
208
210 if all descendant branch heads are closed, but there is another branch head:
209 if all descendant branch heads are closed, but there is another branch head:
211 - update to the tipmost descendant head
210 - update to the tipmost descendant head
212 - "updated to a closed branch head ...." message is displayed
211 - "updated to a closed branch head ...." message is displayed
213 - "N other heads for ...." message is displayed
212 - "N other heads for ...." message is displayed
214
213
215 $ norevtest "all descendant branch heads are closed" clean 3
214 $ norevtest "all descendant branch heads are closed" clean 3
216 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
215 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
217 updated to a closed branch head, because all descendant heads are closed.
216 no open descendant heads on branch "default", updating to a closed head
218 beware of re-opening closed head by subsequent commit here.
217 (committing will reopen the head, use `hg heads .` to see 1 other heads)
219 1 other heads for branch "default"
220 parent=6
218 parent=6
221
219
222 Test updating if all branch heads are closed
220 Test updating if all branch heads are closed
223
221
224 if on the closed branch head:
222 if on the closed branch head:
225 - update to "."
223 - update to "."
226 - "updated to a closed branch head ...." message is displayed
224 - "updated to a closed branch head ...." message is displayed
227 - "all heads of branch ...." message is displayed
225 - "all heads of branch ...." message is displayed
228
226
229 $ hg update -q -C 2
227 $ hg update -q -C 2
230 $ hg commit --close-branch -m 7
228 $ hg commit --close-branch -m 7
231 $ norevtest "all heads of branch default are closed" clean 6
229 $ norevtest "all heads of branch default are closed" clean 6
232 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
230 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
233 updated to a closed branch head, because all descendant heads are closed.
231 no open descendant heads on branch "default", updating to a closed head
234 beware of re-opening closed head by subsequent commit here.
232 (committing will reopen branch "default")
235 all heads for branch "default" are closed.
236 parent=6
233 parent=6
237
234
238 if not on the closed branch head:
235 if not on the closed branch head:
239 - update to the tipmost descendant (closed) head
236 - update to the tipmost descendant (closed) head
240 - "updated to a closed branch head ...." message is displayed
237 - "updated to a closed branch head ...." message is displayed
241 - "all heads of branch ...." message is displayed
238 - "all heads of branch ...." message is displayed
242
239
243 $ norevtest "all heads of branch default are closed" clean 1
240 $ norevtest "all heads of branch default are closed" clean 1
244 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
241 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
245 updated to a closed branch head, because all descendant heads are closed.
242 no open descendant heads on branch "default", updating to a closed head
246 beware of re-opening closed head by subsequent commit here.
243 (committing will reopen branch "default")
247 all heads for branch "default" are closed.
248 parent=7
244 parent=7
249
245
250 $ cd ..
246 $ cd ..
251
247
252 Test updating if "default" branch doesn't exist and no revision is
248 Test updating if "default" branch doesn't exist and no revision is
253 checked out (= "default" is used as current branch)
249 checked out (= "default" is used as current branch)
254
250
255 $ hg init no-default-branch
251 $ hg init no-default-branch
256 $ cd no-default-branch
252 $ cd no-default-branch
257
253
258 $ hg branch foobar
254 $ hg branch foobar
259 marked working directory as branch foobar
255 marked working directory as branch foobar
260 (branches are permanent and global, did you want a bookmark?)
256 (branches are permanent and global, did you want a bookmark?)
261 $ echo a > a
257 $ echo a > a
262 $ hg commit -m "#0" -A
258 $ hg commit -m "#0" -A
263 adding a
259 adding a
264 $ echo 1 >> a
260 $ echo 1 >> a
265 $ hg commit -m "#1"
261 $ hg commit -m "#1"
266 $ hg update -q 0
262 $ hg update -q 0
267 $ echo 3 >> a
263 $ echo 3 >> a
268 $ hg commit -m "#2"
264 $ hg commit -m "#2"
269 created new head
265 created new head
270 $ hg commit --close-branch -m "#3"
266 $ hg commit --close-branch -m "#3"
271
267
272 if there is at least one non-closed branch head:
268 if there is at least one non-closed branch head:
273 - update to the tipmost branch head
269 - update to the tipmost branch head
274
270
275 $ norevtest "non-closed 1 should be chosen" clean null
271 $ norevtest "non-closed 1 should be chosen" clean null
276 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
272 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
277 parent=1
273 parent=1
278
274
279 if all branch heads are closed
275 if all branch heads are closed
280 - update to "tip"
276 - update to "tip"
281 - "updated to a closed branch head ...." message is displayed
277 - "updated to a closed branch head ...." message is displayed
282 - "all heads for branch "XXXX" are closed" message is displayed
278 - "all heads for branch "XXXX" are closed" message is displayed
283
279
284 $ hg update -q -C 1
280 $ hg update -q -C 1
285 $ hg commit --close-branch -m "#4"
281 $ hg commit --close-branch -m "#4"
286
282
287 $ norevtest "all branches are closed" clean null
283 $ norevtest "all branches are closed" clean null
288 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
284 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
289 updated to a closed branch head, because all descendant heads are closed.
285 no open descendant heads on branch "foobar", updating to a closed head
290 beware of re-opening closed head by subsequent commit here.
286 (committing will reopen branch "foobar")
291 all heads for branch "foobar" are closed.
292 parent=4
287 parent=4
293
288
294 $ cd ../b1
289 $ cd ../b1
295
290
296 Test obsolescence behavior
291 Test obsolescence behavior
297 ---------------------------------------------------------------------
292 ---------------------------------------------------------------------
298
293
299 successors should be taken in account when checking head destination
294 successors should be taken in account when checking head destination
300
295
301 $ cat << EOF >> $HGRCPATH
296 $ cat << EOF >> $HGRCPATH
302 > [ui]
297 > [ui]
303 > logtemplate={rev}:{node|short} {desc|firstline}
298 > logtemplate={rev}:{node|short} {desc|firstline}
304 > [experimental]
299 > [experimental]
305 > evolution=createmarkers
300 > evolution=createmarkers
306 > EOF
301 > EOF
307
302
308 Test no-argument update to a successor of an obsoleted changeset
303 Test no-argument update to a successor of an obsoleted changeset
309
304
310 $ hg log -G
305 $ hg log -G
311 o 5:ff252e8273df 5
306 o 5:ff252e8273df 5
312 |
307 |
313 o 4:d047485b3896 4
308 o 4:d047485b3896 4
314 |
309 |
315 | o 3:6efa171f091b 3
310 | o 3:6efa171f091b 3
316 | |
311 | |
317 | | o 2:bd10386d478c 2
312 | | o 2:bd10386d478c 2
318 | |/
313 | |/
319 | @ 1:0786582aa4b1 1
314 | @ 1:0786582aa4b1 1
320 |/
315 |/
321 o 0:60829823a42a 0
316 o 0:60829823a42a 0
322
317
323 $ hg book bm -r 3
318 $ hg book bm -r 3
324 $ hg status
319 $ hg status
325 M foo
320 M foo
326
321
327 We add simple obsolescence marker between 3 and 4 (indirect successors)
322 We add simple obsolescence marker between 3 and 4 (indirect successors)
328
323
329 $ hg id --debug -i -r 3
324 $ hg id --debug -i -r 3
330 6efa171f091b00a3c35edc15d48c52a498929953
325 6efa171f091b00a3c35edc15d48c52a498929953
331 $ hg id --debug -i -r 4
326 $ hg id --debug -i -r 4
332 d047485b3896813b2a624e86201983520f003206
327 d047485b3896813b2a624e86201983520f003206
333 $ hg debugobsolete 6efa171f091b00a3c35edc15d48c52a498929953 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
328 $ hg debugobsolete 6efa171f091b00a3c35edc15d48c52a498929953 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
334 $ hg debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa d047485b3896813b2a624e86201983520f003206
329 $ hg debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa d047485b3896813b2a624e86201983520f003206
335
330
336 Test that 5 is detected as a valid destination from 3 and also accepts moving
331 Test that 5 is detected as a valid destination from 3 and also accepts moving
337 the bookmark (issue4015)
332 the bookmark (issue4015)
338
333
339 $ hg up --quiet --hidden 3
334 $ hg up --quiet --hidden 3
340 $ hg up 5
335 $ hg up 5
341 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
336 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
342 $ hg book bm
337 $ hg book bm
343 moving bookmark 'bm' forward from 6efa171f091b
338 moving bookmark 'bm' forward from 6efa171f091b
344 $ hg bookmarks
339 $ hg bookmarks
345 * bm 5:ff252e8273df
340 * bm 5:ff252e8273df
346
341
347 Test that 4 is detected as the no-argument destination from 3 and also moves
342 Test that 4 is detected as the no-argument destination from 3 and also moves
348 the bookmark with it
343 the bookmark with it
349 $ hg up --quiet 0 # we should be able to update to 3 directly
344 $ hg up --quiet 0 # we should be able to update to 3 directly
350 $ hg up --quiet --hidden 3 # but not implemented yet.
345 $ hg up --quiet --hidden 3 # but not implemented yet.
351 $ hg book -f bm
346 $ hg book -f bm
352 $ hg up
347 $ hg up
353 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
348 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
354 updating bookmark bm
349 updating bookmark bm
355 $ hg book
350 $ hg book
356 * bm 4:d047485b3896
351 * bm 4:d047485b3896
357
352
358 Test that 5 is detected as a valid destination from 1
353 Test that 5 is detected as a valid destination from 1
359 $ hg up --quiet 0 # we should be able to update to 3 directly
354 $ hg up --quiet 0 # we should be able to update to 3 directly
360 $ hg up --quiet --hidden 3 # but not implemented yet.
355 $ hg up --quiet --hidden 3 # but not implemented yet.
361 $ hg up 5
356 $ hg up 5
362 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
357 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
363
358
364 Test that 5 is not detected as a valid destination from 2
359 Test that 5 is not detected as a valid destination from 2
365 $ hg up --quiet 0
360 $ hg up --quiet 0
366 $ hg up --quiet 2
361 $ hg up --quiet 2
367 $ hg up 5
362 $ hg up 5
368 abort: uncommitted changes
363 abort: uncommitted changes
369 (commit or update --clean to discard changes)
364 (commit or update --clean to discard changes)
370 [255]
365 [255]
371
366
372 Test that we don't crash when updating from a pruned changeset (i.e. has no
367 Test that we don't crash when updating from a pruned changeset (i.e. has no
373 successors). Behavior should probably be that we update to the first
368 successors). Behavior should probably be that we update to the first
374 non-obsolete parent but that will be decided later.
369 non-obsolete parent but that will be decided later.
375 $ hg id --debug -r 2
370 $ hg id --debug -r 2
376 bd10386d478cd5a9faf2e604114c8e6da62d3889
371 bd10386d478cd5a9faf2e604114c8e6da62d3889
377 $ hg up --quiet 0
372 $ hg up --quiet 0
378 $ hg up --quiet 2
373 $ hg up --quiet 2
379 $ hg debugobsolete bd10386d478cd5a9faf2e604114c8e6da62d3889
374 $ hg debugobsolete bd10386d478cd5a9faf2e604114c8e6da62d3889
380 $ hg up
375 $ hg up
381 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
376 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
382
377
383 Test experimental revset support
378 Test experimental revset support
384
379
385 $ hg log -r '_destupdate()'
380 $ hg log -r '_destupdate()'
386 2:bd10386d478c 2 (no-eol)
381 2:bd10386d478c 2 (no-eol)
General Comments 0
You need to be logged in to leave comments. Login now