##// END OF EJS Templates
rewriteutil: add pointer to help text when rewrite would cause divergence...
Martin von Zweigbergk -
r48166:8125bcd2 default
parent child Browse files
Show More
@@ -1,242 +1,247 b''
1 1 # rewriteutil.py - utility functions for rewriting changesets
2 2 #
3 3 # Copyright 2017 Octobus <contact@octobus.net>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import re
11 11
12 12 from .i18n import _
13 13 from .node import (
14 14 hex,
15 15 nullrev,
16 16 )
17 17
18 18 from . import (
19 19 error,
20 20 node,
21 21 obsolete,
22 22 obsutil,
23 23 revset,
24 24 scmutil,
25 25 util,
26 26 )
27 27
28 28
29 29 NODE_RE = re.compile(br'\b[0-9a-f]{6,64}\b')
30 30
31 31
32 32 def _formatrevs(repo, revs, maxrevs=4):
33 33 """returns a string summarizing revisions in a decent size
34 34
35 35 If there are few enough revisions, we list them all. Otherwise we display a
36 36 summary of the form:
37 37
38 38 1ea73414a91b and 5 others
39 39 """
40 40 tonode = repo.changelog.node
41 41 numrevs = len(revs)
42 42 if numrevs < maxrevs:
43 43 shorts = [node.short(tonode(r)) for r in revs]
44 44 summary = b', '.join(shorts)
45 45 else:
46 46 first = revs.first()
47 47 summary = _(b'%s and %d others')
48 48 summary %= (node.short(tonode(first)), numrevs - 1)
49 49 return summary
50 50
51 51
52 52 def precheck(repo, revs, action=b'rewrite'):
53 53 """check if revs can be rewritten
54 54 action is used to control the error message.
55 55
56 56 Make sure this function is called after taking the lock.
57 57 """
58 58 if nullrev in revs:
59 59 msg = _(b"cannot %s the null revision") % action
60 60 hint = _(b"no changeset checked out")
61 61 raise error.InputError(msg, hint=hint)
62 62
63 63 if any(util.safehasattr(r, 'rev') for r in revs):
64 64 repo.ui.develwarn(b"rewriteutil.precheck called with ctx not revs")
65 65 revs = (r.rev() for r in revs)
66 66
67 67 if len(repo[None].parents()) > 1:
68 68 raise error.StateError(
69 69 _(b"cannot %s changesets while merging") % action
70 70 )
71 71
72 72 publicrevs = repo.revs(b'%ld and public()', revs)
73 73 if publicrevs:
74 74 summary = _formatrevs(repo, publicrevs)
75 75 msg = _(b"cannot %s public changesets: %s") % (action, summary)
76 76 hint = _(b"see 'hg help phases' for details")
77 77 raise error.InputError(msg, hint=hint)
78 78
79 79 newunstable = disallowednewunstable(repo, revs)
80 80 if newunstable:
81 81 hint = _(b"see 'hg help evolution.instability'")
82 82 raise error.InputError(
83 83 _(b"cannot %s changeset, as that will orphan %d descendants")
84 84 % (action, len(newunstable)),
85 85 hint=hint,
86 86 )
87 87
88 88 if not obsolete.isenabled(repo, obsolete.allowdivergenceopt):
89 89 new_divergence = _find_new_divergence(repo, revs)
90 90 if new_divergence:
91 91 local_ctx, other_ctx, base_ctx = new_divergence
92 92 msg = _(
93 93 b'cannot %s %s, as that creates content-divergence with %s'
94 94 ) % (
95 95 action,
96 96 local_ctx,
97 97 other_ctx,
98 98 )
99 99 if local_ctx.rev() != base_ctx.rev():
100 100 msg += _(b', from %s') % base_ctx
101 101 if repo.ui.verbose:
102 102 if local_ctx.rev() != base_ctx.rev():
103 103 msg += _(
104 104 b'\n changeset %s is a successor of ' b'changeset %s'
105 105 ) % (local_ctx, base_ctx)
106 106 msg += _(
107 107 b'\n changeset %s already has a successor in '
108 108 b'changeset %s\n'
109 109 b' rewriting changeset %s would create '
110 110 b'"content-divergence"\n'
111 111 b' set experimental.evolution.allowdivergence=True to '
112 112 b'skip this check'
113 113 ) % (base_ctx, other_ctx, local_ctx)
114 raise error.InputError(msg)
114 raise error.InputError(
115 msg,
116 hint=_(
117 b"see 'hg help evolution.instability' for details on content-divergence"
118 ),
119 )
115 120 else:
116 121 raise error.InputError(
117 122 msg,
118 123 hint=_(
119 124 b"add --verbose for details or see "
120 125 b"'hg help evolution.instability'"
121 126 ),
122 127 )
123 128
124 129
125 130 def disallowednewunstable(repo, revs):
126 131 """Checks whether editing the revs will create new unstable changesets and
127 132 are we allowed to create them.
128 133
129 134 To allow new unstable changesets, set the config:
130 135 `experimental.evolution.allowunstable=True`
131 136 """
132 137 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
133 138 if allowunstable:
134 139 return revset.baseset()
135 140 return repo.revs(b"(%ld::) - %ld", revs, revs)
136 141
137 142
138 143 def _find_new_divergence(repo, revs):
139 144 obsrevs = repo.revs(b'%ld and obsolete()', revs)
140 145 for r in obsrevs:
141 146 div = find_new_divergence_from(repo, repo[r])
142 147 if div:
143 148 return (repo[r], repo[div[0]], repo[div[1]])
144 149 return None
145 150
146 151
147 152 def find_new_divergence_from(repo, ctx):
148 153 """return divergent revision if rewriting an obsolete cset (ctx) will
149 154 create divergence
150 155
151 156 Returns (<other node>, <common ancestor node>) or None
152 157 """
153 158 if not ctx.obsolete():
154 159 return None
155 160 # We need to check two cases that can cause divergence:
156 161 # case 1: the rev being rewritten has a non-obsolete successor (easily
157 162 # detected by successorssets)
158 163 sset = obsutil.successorssets(repo, ctx.node())
159 164 if sset:
160 165 return (sset[0][0], ctx.node())
161 166 else:
162 167 # case 2: one of the precursors of the rev being revived has a
163 168 # non-obsolete successor (we need divergentsets for this)
164 169 divsets = obsutil.divergentsets(repo, ctx)
165 170 if divsets:
166 171 nsuccset = divsets[0][b'divergentnodes']
167 172 prec = divsets[0][b'commonpredecessor']
168 173 return (nsuccset[0], prec)
169 174 return None
170 175
171 176
172 177 def skip_empty_successor(ui, command):
173 178 empty_successor = ui.config(b'rewrite', b'empty-successor')
174 179 if empty_successor == b'skip':
175 180 return True
176 181 elif empty_successor == b'keep':
177 182 return False
178 183 else:
179 184 raise error.ConfigError(
180 185 _(
181 186 b"%s doesn't know how to handle config "
182 187 b"rewrite.empty-successor=%s (only 'skip' and 'keep' are "
183 188 b"supported)"
184 189 )
185 190 % (command, empty_successor)
186 191 )
187 192
188 193
189 194 def update_hash_refs(repo, commitmsg, pending=None):
190 195 """Replace all obsolete commit hashes in the message with the current hash.
191 196
192 197 If the obsolete commit was split or is divergent, the hash is not replaced
193 198 as there's no way to know which successor to choose.
194 199
195 200 For commands that update a series of commits in the current transaction, the
196 201 new obsolete markers can be considered by setting ``pending`` to a mapping
197 202 of ``pending[oldnode] = [successor_node1, successor_node2,..]``.
198 203 """
199 204 if not pending:
200 205 pending = {}
201 206 cache = {}
202 207 hashes = re.findall(NODE_RE, commitmsg)
203 208 unfi = repo.unfiltered()
204 209 for h in hashes:
205 210 fullnode = scmutil.resolvehexnodeidprefix(unfi, h)
206 211 if fullnode is None:
207 212 continue
208 213 ctx = unfi[fullnode]
209 214 if not ctx.obsolete():
210 215 successors = pending.get(fullnode)
211 216 if successors is None:
212 217 continue
213 218 # obsutil.successorssets() returns a list of list of nodes
214 219 successors = [successors]
215 220 else:
216 221 successors = obsutil.successorssets(repo, ctx.node(), cache=cache)
217 222
218 223 # We can't make any assumptions about how to update the hash if the
219 224 # cset in question was split or diverged.
220 225 if len(successors) == 1 and len(successors[0]) == 1:
221 226 successor = successors[0][0]
222 227 if successor is not None:
223 228 newhash = hex(successor)
224 229 commitmsg = commitmsg.replace(h, newhash[: len(h)])
225 230 else:
226 231 repo.ui.note(
227 232 _(
228 233 b'The stale commit message reference to %s could '
229 234 b'not be updated\n(The referenced commit was dropped)\n'
230 235 )
231 236 % h
232 237 )
233 238 else:
234 239 repo.ui.note(
235 240 _(
236 241 b'The stale commit message reference to %s could '
237 242 b'not be updated\n'
238 243 )
239 244 % h
240 245 )
241 246
242 247 return commitmsg
@@ -1,543 +1,550 b''
1 1 #testcases obsstore-off obsstore-on
2 2
3 3 $ cat << EOF >> $HGRCPATH
4 4 > [extensions]
5 5 > amend=
6 6 > debugdrawdag=$TESTDIR/drawdag.py
7 7 > [diff]
8 8 > git=1
9 9 > EOF
10 10
11 11 #if obsstore-on
12 12 $ cat << EOF >> $HGRCPATH
13 13 > [experimental]
14 14 > evolution.createmarkers=True
15 15 > EOF
16 16 #endif
17 17
18 18 Basic amend
19 19
20 20 $ hg init repo1
21 21 $ cd repo1
22 22 $ hg debugdrawdag <<'EOS'
23 23 > B
24 24 > |
25 25 > A
26 26 > EOS
27 27
28 28 $ hg update B -q
29 29 $ echo 2 >> B
30 30
31 31 $ hg amend
32 32 saved backup bundle to $TESTTMP/repo1/.hg/strip-backup/112478962961-7e959a55-amend.hg (obsstore-off !)
33 33 #if obsstore-off
34 34 $ hg log -p -G --hidden -T '{rev} {node|short} {desc}\n'
35 35 @ 1 be169c7e8dbe B
36 36 | diff --git a/B b/B
37 37 | new file mode 100644
38 38 | --- /dev/null
39 39 | +++ b/B
40 40 | @@ -0,0 +1,1 @@
41 41 | +B2
42 42 |
43 43 o 0 426bada5c675 A
44 44 diff --git a/A b/A
45 45 new file mode 100644
46 46 --- /dev/null
47 47 +++ b/A
48 48 @@ -0,0 +1,1 @@
49 49 +A
50 50 \ No newline at end of file
51 51
52 52 #else
53 53 $ hg log -p -G --hidden -T '{rev} {node|short} {desc}\n'
54 54 @ 2 be169c7e8dbe B
55 55 | diff --git a/B b/B
56 56 | new file mode 100644
57 57 | --- /dev/null
58 58 | +++ b/B
59 59 | @@ -0,0 +1,1 @@
60 60 | +B2
61 61 |
62 62 | x 1 112478962961 B
63 63 |/ diff --git a/B b/B
64 64 | new file mode 100644
65 65 | --- /dev/null
66 66 | +++ b/B
67 67 | @@ -0,0 +1,1 @@
68 68 | +B
69 69 | \ No newline at end of file
70 70 |
71 71 o 0 426bada5c675 A
72 72 diff --git a/A b/A
73 73 new file mode 100644
74 74 --- /dev/null
75 75 +++ b/A
76 76 @@ -0,0 +1,1 @@
77 77 +A
78 78 \ No newline at end of file
79 79
80 80 #endif
81 81
82 82 Nothing changed
83 83
84 84 $ hg amend
85 85 nothing changed
86 86 [1]
87 87
88 88 $ hg amend -d "0 0"
89 89 nothing changed
90 90 [1]
91 91
92 92 $ hg amend -d "Thu Jan 01 00:00:00 1970 UTC"
93 93 nothing changed
94 94 [1]
95 95
96 96 #if obsstore-on
97 97 $ hg init repo-merge-state
98 98 $ cd repo-merge-state
99 99 $ echo a > f
100 100 $ hg ci -Aqm a
101 101 $ echo b > f
102 102 $ hg ci -Aqm b
103 103 $ echo c > f
104 104 $ hg co -m '.^'
105 105 merging f
106 106 warning: conflicts while merging f! (edit, then use 'hg resolve --mark')
107 107 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
108 108 use 'hg resolve' to retry unresolved file merges
109 109 [1]
110 110 $ echo d > f
111 111 $ hg resolve -m f
112 112 (no more unresolved files)
113 113 $ hg ci --amend --config experimental.evolution.allowunstable=True
114 114 1 new orphan changesets
115 115 $ hg resolve -l
116 116 $ cd ..
117 117 #endif
118 118
119 119 Matcher and metadata options
120 120
121 121 $ echo 3 > C
122 122 $ echo 4 > D
123 123 $ hg add C D
124 124 $ hg amend -m NEWMESSAGE -I C
125 125 saved backup bundle to $TESTTMP/repo1/.hg/strip-backup/be169c7e8dbe-7684ddc5-amend.hg (obsstore-off !)
126 126 $ hg log -r . -T '{node|short} {desc} {files}\n'
127 127 c7ba14d9075b NEWMESSAGE B C
128 128 $ echo 5 > E
129 129 $ rm C
130 130 $ hg amend -d '2000 1000' -u 'Foo <foo@example.com>' -A C D
131 131 saved backup bundle to $TESTTMP/repo1/.hg/strip-backup/c7ba14d9075b-b3e76daa-amend.hg (obsstore-off !)
132 132 $ hg log -r . -T '{node|short} {desc} {files} {author} {date}\n'
133 133 14f6c4bcc865 NEWMESSAGE B D Foo <foo@example.com> 2000.01000
134 134
135 135 Amend with editor
136 136
137 137 $ cat > $TESTTMP/prefix.sh <<'EOF'
138 138 > printf 'EDITED: ' > $TESTTMP/msg
139 139 > cat "$1" >> $TESTTMP/msg
140 140 > mv $TESTTMP/msg "$1"
141 141 > EOF
142 142 $ chmod +x $TESTTMP/prefix.sh
143 143
144 144 $ HGEDITOR="sh $TESTTMP/prefix.sh" hg amend --edit
145 145 saved backup bundle to $TESTTMP/repo1/.hg/strip-backup/14f6c4bcc865-6591f15d-amend.hg (obsstore-off !)
146 146 $ hg log -r . -T '{node|short} {desc}\n'
147 147 298f085230c3 EDITED: NEWMESSAGE
148 148 $ HGEDITOR="sh $TESTTMP/prefix.sh" hg amend -e -m MSG
149 149 saved backup bundle to $TESTTMP/repo1/.hg/strip-backup/298f085230c3-d81a6ad3-amend.hg (obsstore-off !)
150 150 $ hg log -r . -T '{node|short} {desc}\n'
151 151 974f07f28537 EDITED: MSG
152 152
153 153 $ echo FOO > $TESTTMP/msg
154 154 $ hg amend -l $TESTTMP/msg -m BAR
155 155 abort: cannot specify both --message and --logfile
156 156 [10]
157 157 $ hg amend -l $TESTTMP/msg
158 158 saved backup bundle to $TESTTMP/repo1/.hg/strip-backup/974f07f28537-edb6470a-amend.hg (obsstore-off !)
159 159 $ hg log -r . -T '{node|short} {desc}\n'
160 160 507be9bdac71 FOO
161 161
162 162 Interactive mode
163 163
164 164 $ touch F G
165 165 $ hg add F G
166 166 $ cat <<EOS | hg amend -i --config ui.interactive=1
167 167 > y
168 168 > n
169 169 > EOS
170 170 diff --git a/F b/F
171 171 new file mode 100644
172 172 examine changes to 'F'?
173 173 (enter ? for help) [Ynesfdaq?] y
174 174
175 175 diff --git a/G b/G
176 176 new file mode 100644
177 177 examine changes to 'G'?
178 178 (enter ? for help) [Ynesfdaq?] n
179 179
180 180 saved backup bundle to $TESTTMP/repo1/.hg/strip-backup/507be9bdac71-c8077452-amend.hg (obsstore-off !)
181 181 $ hg log -r . -T '{files}\n'
182 182 B D F
183 183
184 184 Amend in the middle of a stack
185 185
186 186 $ hg init $TESTTMP/repo2
187 187 $ cd $TESTTMP/repo2
188 188 $ hg debugdrawdag <<'EOS'
189 189 > C
190 190 > |
191 191 > B
192 192 > |
193 193 > A
194 194 > EOS
195 195
196 196 $ hg update -q B
197 197 $ echo 2 >> B
198 198 $ hg amend
199 199 abort: cannot amend changeset, as that will orphan 1 descendants
200 200 (see 'hg help evolution.instability')
201 201 [10]
202 202
203 203 #if obsstore-on
204 204
205 205 With allowunstable, amend could work in the middle of a stack
206 206
207 207 $ cat >> $HGRCPATH <<EOF
208 208 > [experimental]
209 209 > evolution.createmarkers=True
210 210 > evolution.allowunstable=True
211 211 > EOF
212 212
213 213 $ hg amend
214 214 1 new orphan changesets
215 215 $ hg log -T '{rev} {node|short} {desc}\n' -G
216 216 @ 3 be169c7e8dbe B
217 217 |
218 218 | * 2 26805aba1e60 C
219 219 | |
220 220 | x 1 112478962961 B
221 221 |/
222 222 o 0 426bada5c675 A
223 223
224 224 Checking the note stored in the obsmarker
225 225
226 226 $ echo foo > bar
227 227 $ hg add bar
228 228 $ hg amend --note 'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy'
229 229 abort: cannot store a note of more than 255 bytes
230 230 [10]
231 231 $ hg amend --note "adding bar"
232 232 $ hg debugobsolete -r .
233 233 112478962961147124edd43549aedd1a335e44bf be169c7e8dbe21cd10b3d79691cbe7f241e3c21c 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'operation': 'amend', 'user': 'test'}
234 234 be169c7e8dbe21cd10b3d79691cbe7f241e3c21c 16084da537dd8f84cfdb3055c633772269d62e1b 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'note': 'adding bar', 'operation': 'amend', 'user': 'test'}
235 235
236 236 Cannot cause divergence by default
237 237
238 238 $ hg co --hidden 1
239 239 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
240 240 $ hg amend -m divergent
241 241 abort: cannot amend 112478962961, as that creates content-divergence with 16084da537dd
242 242 (add --verbose for details or see 'hg help evolution.instability')
243 243 [10]
244 $ hg amend -m divergent --verbose
245 abort: cannot amend 112478962961, as that creates content-divergence with 16084da537dd
246 changeset 112478962961 already has a successor in changeset 16084da537dd
247 rewriting changeset 112478962961 would create "content-divergence"
248 set experimental.evolution.allowdivergence=True to skip this check
249 (see 'hg help evolution.instability' for details on content-divergence)
250 [10]
244 251 $ hg amend -m divergent --config experimental.evolution.allowdivergence=true
245 252 2 new content-divergent changesets
246 253 #endif
247 254
248 255 Cannot amend public changeset
249 256
250 257 $ hg phase -r A --public
251 258 $ hg update -C -q A
252 259 $ hg amend -m AMEND
253 260 abort: cannot amend public changesets: 426bada5c675
254 261 (see 'hg help phases' for details)
255 262 [10]
256 263
257 264 Amend a merge changeset
258 265
259 266 $ hg init $TESTTMP/repo3
260 267 $ cd $TESTTMP/repo3
261 268 $ hg debugdrawdag <<'EOS'
262 269 > C
263 270 > /|
264 271 > A B
265 272 > EOS
266 273 $ hg update -q C
267 274 $ hg amend -m FOO
268 275 saved backup bundle to $TESTTMP/repo3/.hg/strip-backup/a35c07e8a2a4-15ff4612-amend.hg (obsstore-off !)
269 276 $ rm .hg/localtags
270 277 $ hg log -G -T '{desc}\n'
271 278 @ FOO
272 279 |\
273 280 | o B
274 281 |
275 282 o A
276 283
277 284
278 285 More complete test for status changes (issue5732)
279 286 -------------------------------------------------
280 287
281 288 Generates history of files having 3 states, r0_r1_wc:
282 289
283 290 r0: ground (content/missing)
284 291 r1: old state to be amended (content/missing, where missing means removed)
285 292 wc: changes to be included in r1 (content/missing-tracked/untracked)
286 293
287 294 $ hg init $TESTTMP/wcstates
288 295 $ cd $TESTTMP/wcstates
289 296
290 297 $ "$PYTHON" $TESTDIR/generate-working-copy-states.py state 2 1
291 298 $ hg addremove -q --similarity 0
292 299 $ hg commit -m0
293 300
294 301 $ "$PYTHON" $TESTDIR/generate-working-copy-states.py state 2 2
295 302 $ hg addremove -q --similarity 0
296 303 $ hg commit -m1
297 304
298 305 $ "$PYTHON" $TESTDIR/generate-working-copy-states.py state 2 wc
299 306 $ hg addremove -q --similarity 0
300 307 $ hg forget *_*_*-untracked
301 308 $ rm *_*_missing-*
302 309
303 310 amend r1 to include wc changes
304 311
305 312 $ hg amend
306 313 saved backup bundle to * (glob) (obsstore-off !)
307 314
308 315 clean/modified/removed/added states of the amended revision
309 316
310 317 $ hg status --all --change . 'glob:content1_*_content1-tracked'
311 318 C content1_content1_content1-tracked
312 319 C content1_content2_content1-tracked
313 320 C content1_missing_content1-tracked
314 321 $ hg status --all --change . 'glob:content1_*_content[23]-tracked'
315 322 M content1_content1_content3-tracked
316 323 M content1_content2_content2-tracked
317 324 M content1_content2_content3-tracked
318 325 M content1_missing_content3-tracked
319 326 $ hg status --all --change . 'glob:content1_*_missing-tracked'
320 327 M content1_content2_missing-tracked
321 328 R content1_missing_missing-tracked
322 329 C content1_content1_missing-tracked
323 330 $ hg status --all --change . 'glob:content1_*_*-untracked'
324 331 R content1_content1_content1-untracked
325 332 R content1_content1_content3-untracked
326 333 R content1_content1_missing-untracked
327 334 R content1_content2_content1-untracked
328 335 R content1_content2_content2-untracked
329 336 R content1_content2_content3-untracked
330 337 R content1_content2_missing-untracked
331 338 R content1_missing_content1-untracked
332 339 R content1_missing_content3-untracked
333 340 R content1_missing_missing-untracked
334 341 $ hg status --all --change . 'glob:missing_content2_*'
335 342 A missing_content2_content2-tracked
336 343 A missing_content2_content3-tracked
337 344 A missing_content2_missing-tracked
338 345 $ hg status --all --change . 'glob:missing_missing_*'
339 346 A missing_missing_content3-tracked
340 347
341 348 working directory should be all clean (with some missing/untracked files)
342 349
343 350 $ hg status --all 'glob:*_content?-tracked'
344 351 C content1_content1_content1-tracked
345 352 C content1_content1_content3-tracked
346 353 C content1_content2_content1-tracked
347 354 C content1_content2_content2-tracked
348 355 C content1_content2_content3-tracked
349 356 C content1_missing_content1-tracked
350 357 C content1_missing_content3-tracked
351 358 C missing_content2_content2-tracked
352 359 C missing_content2_content3-tracked
353 360 C missing_missing_content3-tracked
354 361 $ hg status --all 'glob:*_missing-tracked'
355 362 ! content1_content1_missing-tracked
356 363 ! content1_content2_missing-tracked
357 364 ! content1_missing_missing-tracked
358 365 ! missing_content2_missing-tracked
359 366 ! missing_missing_missing-tracked
360 367 $ hg status --all 'glob:*-untracked'
361 368 ? content1_content1_content1-untracked
362 369 ? content1_content1_content3-untracked
363 370 ? content1_content2_content1-untracked
364 371 ? content1_content2_content2-untracked
365 372 ? content1_content2_content3-untracked
366 373 ? content1_missing_content1-untracked
367 374 ? content1_missing_content3-untracked
368 375 ? missing_content2_content2-untracked
369 376 ? missing_content2_content3-untracked
370 377 ? missing_missing_content3-untracked
371 378
372 379 =================================
373 380 Test backup-bundle config option|
374 381 =================================
375 382 $ hg init $TESTTMP/repo4
376 383 $ cd $TESTTMP/repo4
377 384 $ echo a>a
378 385 $ hg ci -Aqma
379 386 $ echo oops>b
380 387 $ hg ci -Aqm "b"
381 388 $ echo partiallyfixed > b
382 389
383 390 #if obsstore-off
384 391 $ hg amend
385 392 saved backup bundle to $TESTTMP/repo4/.hg/strip-backup/95e899acf2ce-f11cb050-amend.hg
386 393 When backup-bundle config option is set:
387 394 $ cat << EOF >> $HGRCPATH
388 395 > [rewrite]
389 396 > backup-bundle = False
390 397 > EOF
391 398 $ echo fixed > b
392 399 $ hg amend
393 400
394 401 #else
395 402 $ hg amend
396 403 When backup-bundle config option is set:
397 404 $ cat << EOF >> $HGRCPATH
398 405 > [rewrite]
399 406 > backup-bundle = False
400 407 > EOF
401 408 $ echo fixed > b
402 409 $ hg amend
403 410
404 411 #endif
405 412 ==========================================
406 413 Test update-timestamp config option|
407 414 ==========================================
408 415
409 416 $ cat >> $HGRCPATH << EOF
410 417 > [extensions]
411 418 > amend=
412 419 > mockmakedate = $TESTDIR/mockmakedate.py
413 420 > EOF
414 421
415 422 $ hg init $TESTTMP/repo5
416 423 $ cd $TESTTMP/repo5
417 424 $ cat <<'EOF' >> .hg/hgrc
418 425 > [command-templates]
419 426 > log = 'user: {user}
420 427 > date: {date|date}
421 428 > summary: {desc|firstline}\n'
422 429 > EOF
423 430
424 431 $ echo a>a
425 432 $ hg ci -Am 'commit 1'
426 433 adding a
427 434
428 435 When updatetimestamp is False
429 436
430 437 $ hg amend --date '1997-1-1 0:1'
431 438 $ hg log --limit 1
432 439 user: test
433 440 date: Wed Jan 01 00:01:00 1997 +0000
434 441 summary: commit 1
435 442
436 443 When update-timestamp is True and no other change than the date
437 444
438 445 $ hg amend --config rewrite.update-timestamp=True
439 446 nothing changed
440 447 [1]
441 448 $ hg log --limit 1
442 449 user: test
443 450 date: Wed Jan 01 00:01:00 1997 +0000
444 451 summary: commit 1
445 452
446 453 When update-timestamp is True and there is other change than the date
447 454 $ hg amend --user foobar --config rewrite.update-timestamp=True
448 455 $ hg log --limit 1
449 456 user: foobar
450 457 date: Thu Jan 01 00:00:02 1970 +0000
451 458 summary: commit 1
452 459
453 460 When date option is applicable and update-timestamp is True
454 461 $ hg amend --date '1998-1-1 0:1' --config rewrite.update-timestamp=True
455 462 $ hg log --limit 1
456 463 user: foobar
457 464 date: Thu Jan 01 00:01:00 1998 +0000
458 465 summary: commit 1
459 466
460 467 Unlike rewrite.update-timestamp, -D/--currentdate always updates the timestamp
461 468
462 469 $ hg amend -D
463 470 $ hg log --limit 1
464 471 user: foobar
465 472 date: Thu Jan 01 00:00:04 1970 +0000
466 473 summary: commit 1
467 474
468 475 $ hg amend -D --config rewrite.update-timestamp=True
469 476 $ hg log --limit 1
470 477 user: foobar
471 478 date: Thu Jan 01 00:00:05 1970 +0000
472 479 summary: commit 1
473 480
474 481 rewrite.update-timestamp can be negated by --no-currentdate
475 482
476 483 $ hg amend --config rewrite.update-timestamp=True --no-currentdate -u baz
477 484 $ hg log --limit 1
478 485 user: baz
479 486 date: Thu Jan 01 00:00:05 1970 +0000
480 487 summary: commit 1
481 488
482 489 Bad combination of date options:
483 490
484 491 $ hg amend -D --date '0 0'
485 492 abort: cannot specify both --date and --currentdate
486 493 [10]
487 494
488 495 Close branch
489 496
490 497 $ hg amend --secret --close-branch
491 498 $ hg log --limit 1 -T 'close={get(extras, "close")}\nphase={phase}\n'
492 499 close=1
493 500 phase=secret
494 501
495 502 $ cd ..
496 503
497 504 Corner case of amend from issue6157:
498 505 - working copy parent has a change to file `a`
499 506 - working copy has the inverse change
500 507 - we amend the working copy parent for files other than `a`
501 508 hg used to include the changes to `a` anyway.
502 509
503 510 $ hg init 6157; cd 6157
504 511 $ echo a > a; echo b > b; hg commit -qAm_
505 512 $ echo a2 > a; hg commit -qm_
506 513 $ hg diff --stat -c .
507 514 a | 2 +-
508 515 1 files changed, 1 insertions(+), 1 deletions(-)
509 516 $ echo a > a; echo b2 > b; hg amend -q b
510 517 $ hg diff --stat -c .
511 518 a | 2 +-
512 519 b | 2 +-
513 520 2 files changed, 2 insertions(+), 2 deletions(-)
514 521
515 522 Modifying a file while the editor is open can cause dirstate corruption
516 523 (issue6233)
517 524
518 525 $ cd $TESTTMP
519 526 $ hg init modify-during-amend; cd modify-during-amend
520 527 $ echo r0 > foo; hg commit -qAm "r0"
521 528 $ echo alpha > foo; hg commit -qm "alpha"
522 529 $ echo beta >> foo
523 530 $ cat > $TESTTMP/touchy_editor.sh <<EOF
524 531 > sleep 1
525 532 > echo delta >> "$TESTTMP/modify-during-amend/foo"
526 533 > sleep 1
527 534 > echo hi > "\$1"
528 535 > sleep 1
529 536 > EOF
530 537 $ HGEDITOR="sh $TESTTMP/touchy_editor.sh" hg commit --amend
531 538 $ if (hg diff -c . | grep 'delta' >/dev/null) || [ -n "$(hg status)" ]; then
532 539 > echo "OK."
533 540 > else
534 541 > echo "Bug detected. 'delta' is not part of the commit OR the wdir"
535 542 > echo "Diff and status before rebuild:"
536 543 > hg diff
537 544 > hg status
538 545 > hg debugrebuilddirstate
539 546 > echo "Diff and status after rebuild:"
540 547 > hg diff
541 548 > hg status
542 549 > fi
543 550 OK.
General Comments 0
You need to be logged in to leave comments. Login now