3141 |
3141 |
3142 # "constant" that convey the backup strategy. |
3142 # "constant" that convey the backup strategy. |
3143 # All set to `discard` if `no-backup` is set do avoid checking |
3143 # All set to `discard` if `no-backup` is set do avoid checking |
3144 # no_backup lower in the code. |
3144 # no_backup lower in the code. |
3145 # These values are ordered for comparison purposes |
3145 # These values are ordered for comparison purposes |
|
3146 backupinteractive = 3 # do backup if interactively modified |
3146 backup = 2 # unconditionally do backup |
3147 backup = 2 # unconditionally do backup |
3147 check = 1 # check if the existing file differs from target |
3148 check = 1 # check if the existing file differs from target |
3148 discard = 0 # never do backup |
3149 discard = 0 # never do backup |
3149 if opts.get('no_backup'): |
3150 if opts.get('no_backup'): |
3150 backup = check = discard |
3151 backupinteractive = backup = check = discard |
|
3152 if interactive: |
|
3153 dsmodifiedbackup = backupinteractive |
|
3154 else: |
|
3155 dsmodifiedbackup = backup |
|
3156 tobackup = set() |
3151 |
3157 |
3152 backupanddel = actions['remove'] |
3158 backupanddel = actions['remove'] |
3153 if not opts.get('no_backup'): |
3159 if not opts.get('no_backup'): |
3154 backupanddel = actions['drop'] |
3160 backupanddel = actions['drop'] |
3155 |
3161 |
3163 # Modified compared to target, no local change |
3169 # Modified compared to target, no local change |
3164 (modified, actions['revert'], discard), |
3170 (modified, actions['revert'], discard), |
3165 # Modified compared to target, but local file is deleted |
3171 # Modified compared to target, but local file is deleted |
3166 (deleted, actions['revert'], discard), |
3172 (deleted, actions['revert'], discard), |
3167 # Modified compared to target, local change |
3173 # Modified compared to target, local change |
3168 (dsmodified, actions['revert'], backup), |
3174 (dsmodified, actions['revert'], dsmodifiedbackup), |
3169 # Added since target |
3175 # Added since target |
3170 (added, actions['remove'], discard), |
3176 (added, actions['remove'], discard), |
3171 # Added in working directory |
3177 # Added in working directory |
3172 (dsadded, actions['forget'], discard), |
3178 (dsadded, actions['forget'], discard), |
3173 # Added since target, have local modification |
3179 # Added since target, have local modification |
3198 for table, (xlist, msg), dobackup in disptable: |
3204 for table, (xlist, msg), dobackup in disptable: |
3199 if abs not in table: |
3205 if abs not in table: |
3200 continue |
3206 continue |
3201 if xlist is not None: |
3207 if xlist is not None: |
3202 xlist.append(abs) |
3208 xlist.append(abs) |
3203 if dobackup and (backup <= dobackup |
3209 if dobackup: |
3204 or wctx[abs].cmp(ctx[abs])): |
3210 # If in interactive mode, don't automatically create |
|
3211 # .orig files (issue4793) |
|
3212 if dobackup == backupinteractive: |
|
3213 tobackup.add(abs) |
|
3214 elif (backup <= dobackup or wctx[abs].cmp(ctx[abs])): |
3205 bakname = scmutil.origpath(ui, repo, rel) |
3215 bakname = scmutil.origpath(ui, repo, rel) |
3206 ui.note(_('saving current version of %s as %s\n') % |
3216 ui.note(_('saving current version of %s as %s\n') % |
3207 (rel, bakname)) |
3217 (rel, bakname)) |
3208 if not opts.get('dry_run'): |
3218 if not opts.get('dry_run'): |
3209 if interactive: |
3219 if interactive: |
3219 break |
3229 break |
3220 |
3230 |
3221 if not opts.get('dry_run'): |
3231 if not opts.get('dry_run'): |
3222 needdata = ('revert', 'add', 'undelete') |
3232 needdata = ('revert', 'add', 'undelete') |
3223 _revertprefetch(repo, ctx, *[actions[name][0] for name in needdata]) |
3233 _revertprefetch(repo, ctx, *[actions[name][0] for name in needdata]) |
3224 _performrevert(repo, parents, ctx, actions, interactive) |
3234 _performrevert(repo, parents, ctx, actions, interactive, tobackup) |
3225 |
3235 |
3226 if targetsubs: |
3236 if targetsubs: |
3227 # Revert the subrepos on the revert list |
3237 # Revert the subrepos on the revert list |
3228 for sub in targetsubs: |
3238 for sub in targetsubs: |
3229 try: |
3239 try: |
3234 |
3244 |
3235 def _revertprefetch(repo, ctx, *files): |
3245 def _revertprefetch(repo, ctx, *files): |
3236 """Let extension changing the storage layer prefetch content""" |
3246 """Let extension changing the storage layer prefetch content""" |
3237 pass |
3247 pass |
3238 |
3248 |
3239 def _performrevert(repo, parents, ctx, actions, interactive=False): |
3249 def _performrevert(repo, parents, ctx, actions, interactive=False, |
|
3250 tobackup=None): |
3240 """function that actually perform all the actions computed for revert |
3251 """function that actually perform all the actions computed for revert |
3241 |
3252 |
3242 This is an independent function to let extension to plug in and react to |
3253 This is an independent function to let extension to plug in and react to |
3243 the imminent revert. |
3254 the imminent revert. |
3244 |
3255 |
3314 |
3325 |
3315 except patch.PatchError as err: |
3326 except patch.PatchError as err: |
3316 raise error.Abort(_('error parsing patch: %s') % err) |
3327 raise error.Abort(_('error parsing patch: %s') % err) |
3317 |
3328 |
3318 newlyaddedandmodifiedfiles = newandmodified(chunks, originalchunks) |
3329 newlyaddedandmodifiedfiles = newandmodified(chunks, originalchunks) |
|
3330 if tobackup is None: |
|
3331 tobackup = set() |
3319 # Apply changes |
3332 # Apply changes |
3320 fp = stringio() |
3333 fp = stringio() |
3321 for c in chunks: |
3334 for c in chunks: |
|
3335 # Create a backup file only if this hunk should be backed up |
|
3336 if ishunk(c) and c.header.filename() in tobackup: |
|
3337 abs = c.header.filename() |
|
3338 target = repo.wjoin(abs) |
|
3339 bakname = scmutil.origpath(repo.ui, repo, m.rel(abs)) |
|
3340 util.copyfile(target, bakname) |
|
3341 tobackup.remove(abs) |
3322 c.write(fp) |
3342 c.write(fp) |
3323 dopatch = fp.tell() |
3343 dopatch = fp.tell() |
3324 fp.seek(0) |
3344 fp.seek(0) |
3325 if dopatch: |
3345 if dopatch: |
3326 try: |
3346 try: |