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)): |