Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/commands.py @ 21979:c2863cfe8a8a
graft: allow regrafting ancestors with --force (issue3220)
author | Siddharth Agarwal <sid0@fb.com> |
---|---|
date | Fri, 25 Jul 2014 18:21:16 -0700 |
parents | dccbf52ffe9f |
children | f4e5753745e9 |
comparison
equal
deleted
inserted
replaced
21978:c21c1c8c2017 | 21979:c2863cfe8a8a |
---|---|
3052 'graft', | 3052 'graft', |
3053 [('r', 'rev', [], _('revisions to graft'), _('REV')), | 3053 [('r', 'rev', [], _('revisions to graft'), _('REV')), |
3054 ('c', 'continue', False, _('resume interrupted graft')), | 3054 ('c', 'continue', False, _('resume interrupted graft')), |
3055 ('e', 'edit', False, _('invoke editor on commit messages')), | 3055 ('e', 'edit', False, _('invoke editor on commit messages')), |
3056 ('', 'log', None, _('append graft info to log message')), | 3056 ('', 'log', None, _('append graft info to log message')), |
3057 ('f', 'force', False, _('force graft')), | |
3057 ('D', 'currentdate', False, | 3058 ('D', 'currentdate', False, |
3058 _('record the current date as commit date')), | 3059 _('record the current date as commit date')), |
3059 ('U', 'currentuser', False, | 3060 ('U', 'currentuser', False, |
3060 _('record the current user as committer'), _('DATE'))] | 3061 _('record the current user as committer'), _('DATE'))] |
3061 + commitopts2 + mergetoolopts + dryrunopts, | 3062 + commitopts2 + mergetoolopts + dryrunopts, |
3074 | 3075 |
3075 If --log is specified, log messages will have a comment appended | 3076 If --log is specified, log messages will have a comment appended |
3076 of the form:: | 3077 of the form:: |
3077 | 3078 |
3078 (grafted from CHANGESETHASH) | 3079 (grafted from CHANGESETHASH) |
3080 | |
3081 If --force is specified, revisions will be grafted even if they | |
3082 are already ancestors of or have been grafted to the destination. | |
3083 This is useful when the revisions have since been backed out. | |
3079 | 3084 |
3080 If a graft merge results in conflicts, the graft process is | 3085 If a graft merge results in conflicts, the graft process is |
3081 interrupted so that the current merge can be manually resolved. | 3086 interrupted so that the current merge can be manually resolved. |
3082 Once all conflicts are addressed, the graft process can be | 3087 Once all conflicts are addressed, the graft process can be |
3083 continued with the -c/--continue option. | 3088 continued with the -c/--continue option. |
3149 revs.remove(rev) | 3154 revs.remove(rev) |
3150 if not revs: | 3155 if not revs: |
3151 return -1 | 3156 return -1 |
3152 | 3157 |
3153 # check for ancestors of dest branch | 3158 # check for ancestors of dest branch |
3154 crev = repo['.'].rev() | 3159 if not opts.get('force'): |
3155 ancestors = repo.changelog.ancestors([crev], inclusive=True) | 3160 crev = repo['.'].rev() |
3156 # Cannot use x.remove(y) on smart set, this has to be a list. | 3161 ancestors = repo.changelog.ancestors([crev], inclusive=True) |
3157 # XXX make this lazy in the future | 3162 # Cannot use x.remove(y) on smart set, this has to be a list. |
3158 revs = list(revs) | 3163 # XXX make this lazy in the future |
3159 # don't mutate while iterating, create a copy | 3164 revs = list(revs) |
3160 for rev in list(revs): | 3165 # don't mutate while iterating, create a copy |
3161 if rev in ancestors: | 3166 for rev in list(revs): |
3162 ui.warn(_('skipping ancestor revision %s\n') % rev) | 3167 if rev in ancestors: |
3163 # XXX remove on list is slow | 3168 ui.warn(_('skipping ancestor revision %s\n') % rev) |
3164 revs.remove(rev) | 3169 # XXX remove on list is slow |
3165 if not revs: | 3170 revs.remove(rev) |
3166 return -1 | 3171 if not revs: |
3167 | 3172 return -1 |
3168 # analyze revs for earlier grafts | 3173 |
3169 ids = {} | 3174 # analyze revs for earlier grafts |
3170 for ctx in repo.set("%ld", revs): | 3175 ids = {} |
3171 ids[ctx.hex()] = ctx.rev() | 3176 for ctx in repo.set("%ld", revs): |
3172 n = ctx.extra().get('source') | 3177 ids[ctx.hex()] = ctx.rev() |
3173 if n: | 3178 n = ctx.extra().get('source') |
3174 ids[n] = ctx.rev() | 3179 if n: |
3175 | 3180 ids[n] = ctx.rev() |
3176 # check ancestors for earlier grafts | 3181 |
3177 ui.debug('scanning for duplicate grafts\n') | 3182 # check ancestors for earlier grafts |
3178 | 3183 ui.debug('scanning for duplicate grafts\n') |
3179 for rev in repo.changelog.findmissingrevs(revs, [crev]): | 3184 |
3180 ctx = repo[rev] | 3185 for rev in repo.changelog.findmissingrevs(revs, [crev]): |
3181 n = ctx.extra().get('source') | 3186 ctx = repo[rev] |
3182 if n in ids: | 3187 n = ctx.extra().get('source') |
3183 r = repo[n].rev() | 3188 if n in ids: |
3184 if r in revs: | 3189 r = repo[n].rev() |
3185 ui.warn(_('skipping revision %s (already grafted to %s)\n') | 3190 if r in revs: |
3186 % (r, rev)) | 3191 ui.warn(_('skipping revision %s (already grafted to %s)\n') |
3192 % (r, rev)) | |
3193 revs.remove(r) | |
3194 elif ids[n] in revs: | |
3195 ui.warn(_('skipping already grafted revision %s ' | |
3196 '(%s also has origin %d)\n') % (ids[n], rev, r)) | |
3197 revs.remove(ids[n]) | |
3198 elif ctx.hex() in ids: | |
3199 r = ids[ctx.hex()] | |
3200 ui.warn(_('skipping already grafted revision %s ' | |
3201 '(was grafted from %d)\n') % (r, rev)) | |
3187 revs.remove(r) | 3202 revs.remove(r) |
3188 elif ids[n] in revs: | 3203 if not revs: |
3189 ui.warn(_('skipping already grafted revision %s ' | 3204 return -1 |
3190 '(%s also has origin %d)\n') % (ids[n], rev, r)) | |
3191 revs.remove(ids[n]) | |
3192 elif ctx.hex() in ids: | |
3193 r = ids[ctx.hex()] | |
3194 ui.warn(_('skipping already grafted revision %s ' | |
3195 '(was grafted from %d)\n') % (r, rev)) | |
3196 revs.remove(r) | |
3197 if not revs: | |
3198 return -1 | |
3199 | 3205 |
3200 wlock = repo.wlock() | 3206 wlock = repo.wlock() |
3201 try: | 3207 try: |
3202 current = repo['.'] | 3208 current = repo['.'] |
3203 for pos, ctx in enumerate(repo.set("%ld", revs)): | 3209 for pos, ctx in enumerate(repo.set("%ld", revs)): |