Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/cmdutil.py @ 41987:c1d83d916e85
revert: option to choose what to keep, not what to discard
I know the you (the reader) are probably tired of discussing how `hg
revert -i -r .` should behave and so am I. And I know I'm one of the
people who argued that showing the diff from the working copy to the
parent was confusing. I think it is less confusing now that we show
the diff from the parent to the working copy, but I still find it
confusing. I think showing the diff of hunks to keep might make it
easier to understand. So that's what this patch provides an option
for.
One argument doing it this way is that most people seem to find `hg
split` natural. I suspect that is because it shows the forward diff
(from parent commit to the commit) and asks you what to put in the
first commit. I think the new "keep" mode for revert (this patch)
matches that.
In "keep" mode, all the changes are still selected by default. That
means that `hg revert -i` followed by 'A' (keep all) (or 'c' in
curses) will be different from `hg revert -a`. That's mostly because
that was simplest. It can also be argued that it's safest. But it can
also be argued that it should be consistent with `hg revert -a`.
Note that in this mode, you can edit the hunks and it will do what you
expect (e.g. add new lines to your file if you added a new lines when
editing). The test case shows that that works.
Differential Revision: https://phab.mercurial-scm.org/D6125
author | Martin von Zweigbergk <martinvonz@google.com> |
---|---|
date | Tue, 12 Mar 2019 14:17:41 -0700 |
parents | b1bc6e5f5249 |
children | 550a172a603b |
comparison
equal
deleted
inserted
replaced
41986:95e4ae86329f | 41987:c1d83d916e85 |
---|---|
3174 diffopts = patch.difffeatureopts(repo.ui, whitespace=True, | 3174 diffopts = patch.difffeatureopts(repo.ui, whitespace=True, |
3175 section='commands', | 3175 section='commands', |
3176 configprefix='revert.interactive.') | 3176 configprefix='revert.interactive.') |
3177 diffopts.nodates = True | 3177 diffopts.nodates = True |
3178 diffopts.git = True | 3178 diffopts.git = True |
3179 operation = 'discard' | 3179 operation = 'apply' |
3180 reversehunks = True | 3180 if node == parent: |
3181 if node != parent: | 3181 if repo.ui.configbool('experimental', |
3182 operation = 'apply' | 3182 'revert.interactive.select-to-keep'): |
3183 reversehunks = False | 3183 operation = 'keep' |
3184 if reversehunks: | 3184 else: |
3185 operation = 'discard' | |
3186 | |
3187 if operation == 'apply': | |
3188 diff = patch.diff(repo, None, ctx.node(), m, opts=diffopts) | |
3189 else: | |
3185 diff = patch.diff(repo, ctx.node(), None, m, opts=diffopts) | 3190 diff = patch.diff(repo, ctx.node(), None, m, opts=diffopts) |
3186 else: | |
3187 diff = patch.diff(repo, None, ctx.node(), m, opts=diffopts) | |
3188 originalchunks = patch.parsepatch(diff) | 3191 originalchunks = patch.parsepatch(diff) |
3189 | 3192 |
3190 try: | 3193 try: |
3191 | 3194 |
3192 chunks, opts = recordfilter(repo.ui, originalchunks, | 3195 chunks, opts = recordfilter(repo.ui, originalchunks, |
3193 operation=operation) | 3196 operation=operation) |
3194 if reversehunks: | 3197 if operation == 'discard': |
3195 chunks = patch.reversehunks(chunks) | 3198 chunks = patch.reversehunks(chunks) |
3196 | 3199 |
3197 except error.PatchError as err: | 3200 except error.PatchError as err: |
3198 raise error.Abort(_('error parsing patch: %s') % err) | 3201 raise error.Abort(_('error parsing patch: %s') % err) |
3199 | 3202 |
3203 # Apply changes | 3206 # Apply changes |
3204 fp = stringio() | 3207 fp = stringio() |
3205 # chunks are serialized per file, but files aren't sorted | 3208 # chunks are serialized per file, but files aren't sorted |
3206 for f in sorted(set(c.header.filename() for c in chunks if ishunk(c))): | 3209 for f in sorted(set(c.header.filename() for c in chunks if ishunk(c))): |
3207 prntstatusmsg('revert', f) | 3210 prntstatusmsg('revert', f) |
3211 files = set() | |
3208 for c in chunks: | 3212 for c in chunks: |
3209 if ishunk(c): | 3213 if ishunk(c): |
3210 abs = c.header.filename() | 3214 abs = c.header.filename() |
3211 # Create a backup file only if this hunk should be backed up | 3215 # Create a backup file only if this hunk should be backed up |
3212 if c.header.filename() in tobackup: | 3216 if c.header.filename() in tobackup: |
3213 target = repo.wjoin(abs) | 3217 target = repo.wjoin(abs) |
3214 bakname = scmutil.backuppath(repo.ui, repo, abs) | 3218 bakname = scmutil.backuppath(repo.ui, repo, abs) |
3215 util.copyfile(target, bakname) | 3219 util.copyfile(target, bakname) |
3216 tobackup.remove(abs) | 3220 tobackup.remove(abs) |
3221 if abs not in files: | |
3222 files.add(abs) | |
3223 if operation == 'keep': | |
3224 checkout(abs) | |
3217 c.write(fp) | 3225 c.write(fp) |
3218 dopatch = fp.tell() | 3226 dopatch = fp.tell() |
3219 fp.seek(0) | 3227 fp.seek(0) |
3220 if dopatch: | 3228 if dopatch: |
3221 try: | 3229 try: |