42 if any(util.safehasattr(r, 'rev') for r in revs): |
42 if any(util.safehasattr(r, 'rev') for r in revs): |
43 repo.ui.develwarn(b"rewriteutil.precheck called with ctx not revs") |
43 repo.ui.develwarn(b"rewriteutil.precheck called with ctx not revs") |
44 revs = (r.rev() for r in revs) |
44 revs = (r.rev() for r in revs) |
45 |
45 |
46 if len(repo[None].parents()) > 1: |
46 if len(repo[None].parents()) > 1: |
47 raise error.StateError(_(b"cannot %s changesets while merging") % action) |
47 raise error.StateError( |
|
48 _(b"cannot %s changesets while merging") % action |
|
49 ) |
48 |
50 |
49 publicrevs = repo.revs(b'%ld and public()', revs) |
51 publicrevs = repo.revs(b'%ld and public()', revs) |
50 if publicrevs: |
52 if publicrevs: |
51 msg = _(b"cannot %s public changesets") % action |
53 msg = _(b"cannot %s public changesets") % action |
52 hint = _(b"see 'hg help phases' for details") |
54 hint = _(b"see 'hg help phases' for details") |
57 hint = _(b"see 'hg help evolution.instability'") |
59 hint = _(b"see 'hg help evolution.instability'") |
58 raise error.InputError( |
60 raise error.InputError( |
59 _(b"cannot %s changeset with children") % action, hint=hint |
61 _(b"cannot %s changeset with children") % action, hint=hint |
60 ) |
62 ) |
61 |
63 |
|
64 if not obsolete.isenabled(repo, obsolete.allowdivergenceopt): |
|
65 new_divergence = _find_new_divergence(repo, revs) |
|
66 if new_divergence: |
|
67 local_ctx, other_ctx, base_ctx = new_divergence |
|
68 msg = _( |
|
69 b'cannot %s %s, as that creates content-divergence with %s' |
|
70 ) % ( |
|
71 action, |
|
72 local_ctx, |
|
73 other_ctx, |
|
74 ) |
|
75 if local_ctx.rev() != base_ctx.rev(): |
|
76 msg += _(b', from %s') % base_ctx |
|
77 if repo.ui.verbose: |
|
78 if local_ctx.rev() != base_ctx.rev(): |
|
79 msg += _( |
|
80 b'\n changeset %s is a successor of ' b'changeset %s' |
|
81 ) % (local_ctx, base_ctx) |
|
82 msg += _( |
|
83 b'\n changeset %s already has a successor in ' |
|
84 b'changeset %s\n' |
|
85 b' rewriting changeset %s would create ' |
|
86 b'"content-divergence"\n' |
|
87 b' set experimental.evolution.allowdivergence=True to ' |
|
88 b'skip this check' |
|
89 ) % (base_ctx, other_ctx, local_ctx) |
|
90 raise error.InputError(msg) |
|
91 else: |
|
92 raise error.InputError( |
|
93 msg, hint=_(b"add --verbose for details") |
|
94 ) |
|
95 |
62 |
96 |
63 def disallowednewunstable(repo, revs): |
97 def disallowednewunstable(repo, revs): |
64 """Checks whether editing the revs will create new unstable changesets and |
98 """Checks whether editing the revs will create new unstable changesets and |
65 are we allowed to create them. |
99 are we allowed to create them. |
66 |
100 |
69 """ |
103 """ |
70 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt) |
104 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt) |
71 if allowunstable: |
105 if allowunstable: |
72 return revset.baseset() |
106 return revset.baseset() |
73 return repo.revs(b"(%ld::) - %ld", revs, revs) |
107 return repo.revs(b"(%ld::) - %ld", revs, revs) |
|
108 |
|
109 |
|
110 def _find_new_divergence(repo, revs): |
|
111 obsrevs = repo.revs(b'%ld and obsolete()', revs) |
|
112 for r in obsrevs: |
|
113 div = find_new_divergence_from(repo, repo[r]) |
|
114 if div: |
|
115 return (repo[r], repo[div[0]], repo[div[1]]) |
|
116 return None |
|
117 |
|
118 |
|
119 def find_new_divergence_from(repo, ctx): |
|
120 """return divergent revision if rewriting an obsolete cset (ctx) will |
|
121 create divergence |
|
122 |
|
123 Returns (<other node>, <common ancestor node>) or None |
|
124 """ |
|
125 if not ctx.obsolete(): |
|
126 return None |
|
127 # We need to check two cases that can cause divergence: |
|
128 # case 1: the rev being rewritten has a non-obsolete successor (easily |
|
129 # detected by successorssets) |
|
130 sset = obsutil.successorssets(repo, ctx.node()) |
|
131 if sset: |
|
132 return (sset[0][0], ctx.node()) |
|
133 else: |
|
134 # case 2: one of the precursors of the rev being revived has a |
|
135 # non-obsolete successor (we need divergentsets for this) |
|
136 divsets = obsutil.divergentsets(repo, ctx) |
|
137 if divsets: |
|
138 nsuccset = divsets[0][b'divergentnodes'] |
|
139 prec = divsets[0][b'commonpredecessor'] |
|
140 return (nsuccset[0], prec) |
|
141 return None |
74 |
142 |
75 |
143 |
76 def skip_empty_successor(ui, command): |
144 def skip_empty_successor(ui, command): |
77 empty_successor = ui.config(b'rewrite', b'empty-successor') |
145 empty_successor = ui.config(b'rewrite', b'empty-successor') |
78 if empty_successor == b'skip': |
146 if empty_successor == b'skip': |