comparison mercurial/commands.py @ 21553:bee0e1cffdd3

import: add --partial flag to create a changeset despite failed hunks The `hg import` command gains a `--partial` flag. When specified, a commit will always be created from a patch import. Any hunk that fails to apply will create .rej file, same as what `hg qimport` would do. This change is mainly aimed at preserving changeset metadata when applying a patch, something very important for reviewers. In case of failure with `--partial`, `hg import` returns 1 and the following message is displayed: patch applied partially (fix the .rej files and run `hg commit --amend`) When multiple patches are imported, we stop at the first one with failed hunks. In the future, someone may feel brave enough to tackle a --continue flag to import.
author Pierre-Yves David <pierre-yves.david@fb.com>
date Thu, 08 May 2014 17:08:17 -0700
parents 61151f429a5f
children 652e07debf10
comparison
equal deleted inserted replaced
21552:61151f429a5f 21553:bee0e1cffdd3
3683 _('skip check for outstanding uncommitted changes (DEPRECATED)')), 3683 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3684 ('', 'no-commit', None, 3684 ('', 'no-commit', None,
3685 _("don't commit, just update the working directory")), 3685 _("don't commit, just update the working directory")),
3686 ('', 'bypass', None, 3686 ('', 'bypass', None,
3687 _("apply patch without touching the working directory")), 3687 _("apply patch without touching the working directory")),
3688 ('', 'partial', None,
3689 _('commit even if some hunks fail')),
3688 ('', 'exact', None, 3690 ('', 'exact', None,
3689 _('apply patch to the nodes from which it was generated')), 3691 _('apply patch to the nodes from which it was generated')),
3690 ('', 'import-branch', None, 3692 ('', 'import-branch', None,
3691 _('use any branch information in patch (implied by --exact)'))] + 3693 _('use any branch information in patch (implied by --exact)'))] +
3692 commitopts + commitopts2 + similarityopts, 3694 commitopts + commitopts2 + similarityopts,
3724 revision. 3726 revision.
3725 3727
3726 With -s/--similarity, hg will attempt to discover renames and 3728 With -s/--similarity, hg will attempt to discover renames and
3727 copies in the patch in the same way as :hg:`addremove`. 3729 copies in the patch in the same way as :hg:`addremove`.
3728 3730
3731 Use --partial to ensure a changeset will be created from the patch
3732 even if some hunks fail to apply. Hunks that fail to apply will be
3733 written to a <target-file>.rej file. Conflicts can then be resolved
3734 by hand before :hg:`commit --amend` is run to update the created
3735 changeset. This flag exists to let people import patches that
3736 partially apply without losing the associated metadata (author,
3737 date, description, ...), Note that when none of the hunk applies
3738 cleanly, :hg:`import --partial` will create an empty changeset,
3739 importing only the patch metadata.
3740
3729 To read a patch from standard input, use "-" as the patch name. If 3741 To read a patch from standard input, use "-" as the patch name. If
3730 a URL is specified, the patch will be downloaded from it. 3742 a URL is specified, the patch will be downloaded from it.
3731 See :hg:`help dates` for a list of formats valid for -d/--date. 3743 See :hg:`help dates` for a list of formats valid for -d/--date.
3732 3744
3733 .. container:: verbose 3745 .. container:: verbose
3749 - attempt to exactly restore an exported changeset (not always 3761 - attempt to exactly restore an exported changeset (not always
3750 possible):: 3762 possible)::
3751 3763
3752 hg import --exact proposed-fix.patch 3764 hg import --exact proposed-fix.patch
3753 3765
3754 Returns 0 on success. 3766 Returns 0 on success, 1 on partial success (see --partial).
3755 """ 3767 """
3756 3768
3757 if not patch1: 3769 if not patch1:
3758 raise util.Abort(_('need at least one patch to import')) 3770 raise util.Abort(_('need at least one patch to import'))
3759 3771
3781 cmdutil.bailifchanged(repo) 3793 cmdutil.bailifchanged(repo)
3782 3794
3783 base = opts["base"] 3795 base = opts["base"]
3784 wlock = lock = tr = None 3796 wlock = lock = tr = None
3785 msgs = [] 3797 msgs = []
3798 ret = 0
3786 3799
3787 3800
3788 try: 3801 try:
3789 try: 3802 try:
3790 wlock = repo.wlock() 3803 wlock = repo.wlock()
3802 ui.status(_('applying %s\n') % patchurl) 3815 ui.status(_('applying %s\n') % patchurl)
3803 patchfile = hg.openpath(ui, patchurl) 3816 patchfile = hg.openpath(ui, patchurl)
3804 3817
3805 haspatch = False 3818 haspatch = False
3806 for hunk in patch.split(patchfile): 3819 for hunk in patch.split(patchfile):
3807 (msg, node) = cmdutil.tryimportone(ui, repo, hunk, parents, 3820 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3808 opts, msgs, hg.clean) 3821 parents, opts,
3822 msgs, hg.clean)
3809 if msg: 3823 if msg:
3810 haspatch = True 3824 haspatch = True
3811 ui.note(msg + '\n') 3825 ui.note(msg + '\n')
3812 if update or opts.get('exact'): 3826 if update or opts.get('exact'):
3813 parents = repo.parents() 3827 parents = repo.parents()
3814 else: 3828 else:
3815 parents = [repo[node]] 3829 parents = [repo[node]]
3830 if rej:
3831 ui.write_err(_("patch applied partially\n"))
3832 ui.write_err(("(fix the .rej files and run "
3833 "`hg commit --amend`)\n"))
3834 ret = 1
3835 break
3816 3836
3817 if not haspatch: 3837 if not haspatch:
3818 raise util.Abort(_('%s: no diffs found') % patchurl) 3838 raise util.Abort(_('%s: no diffs found') % patchurl)
3819 3839
3820 if tr: 3840 if tr:
3821 tr.close() 3841 tr.close()
3822 if msgs: 3842 if msgs:
3823 repo.savecommitmessage('\n* * *\n'.join(msgs)) 3843 repo.savecommitmessage('\n* * *\n'.join(msgs))
3844 return ret
3824 except: # re-raises 3845 except: # re-raises
3825 # wlock.release() indirectly calls dirstate.write(): since 3846 # wlock.release() indirectly calls dirstate.write(): since
3826 # we're crashing, we do not want to change the working dir 3847 # we're crashing, we do not want to change the working dir
3827 # parent after all, so make sure it writes nothing 3848 # parent after all, so make sure it writes nothing
3828 repo.dirstate.invalidate() 3849 repo.dirstate.invalidate()