Print conflict details with the new infrastructure (bug #11181)
[stgit] / stgit / commands / pick.py
CommitLineData
0618ea9c
CM
1__copyright__ = """
2Copyright (C) 2005, Catalin Marinas <catalin.marinas@gmail.com>
3
4This program is free software; you can redistribute it and/or modify
5it under the terms of the GNU General Public License version 2 as
6published by the Free Software Foundation.
7
8This program is distributed in the hope that it will be useful,
9but WITHOUT ANY WARRANTY; without even the implied warranty of
10MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11GNU General Public License for more details.
12
13You should have received a copy of the GNU General Public License
14along with this program; if not, write to the Free Software
15Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16"""
17
18import sys, os
575bbdae 19from stgit.argparse import opt
0618ea9c
CM
20from stgit.commands.common import *
21from stgit.utils import *
5e888f30 22from stgit.out import *
6c8a90e1 23from stgit import argparse, stack, git
8fce9909 24from stgit.stack import Series
0618ea9c 25
575bbdae 26help = 'Import a patch from a different branch or a commit object'
33ff9cdd 27kind = 'patch'
575bbdae
KH
28usage = ['[options] ([<patch1>] [<patch2>] [<patch3>..<patch4>])|<commit>']
29description = """
074f71bb
CM
30Import one or more patches from a different branch or a commit object
31into the current series. By default, the name of the imported patch is
32used as the name of the current patch. It can be overridden with the
33'--name' option. A commit object can be reverted with the '--reverse'
34option. The log and author information are those of the commit
35object."""
0618ea9c 36
6c8a90e1
KH
37args = [argparse.patch_range(argparse.applied_patches,
38 argparse.unapplied_patches,
39 argparse.hidden_patches)]
575bbdae
KH
40options = [
41 opt('-n', '--name',
42 short = 'Use NAME as the patch name'),
6c8a90e1 43 opt('-B', '--ref-branch', args = [argparse.stg_branches],
575bbdae
KH
44 short = 'Pick patches from BRANCH'),
45 opt('-r', '--reverse', action = 'store_true',
46 short = 'Reverse the commit object before importing'),
6c8a90e1 47 opt('-p', '--parent', metavar = 'COMMITID', args = [argparse.commit],
575bbdae
KH
48 short = 'Use COMMITID as parent'),
49 opt('-x', '--expose', action = 'store_true',
50 short = 'Append the imported commit id to the patch log'),
51 opt('--fold', action = 'store_true',
52 short = 'Fold the commit object into the current patch'),
53 opt('--update', action = 'store_true',
54 short = 'Like fold but only update the current patch files'),
55 opt('--unapplied', action = 'store_true',
56 short = 'Keep the patch unapplied')]
57
117ed129 58directory = DirectoryGotoToplevel(log = True)
0618ea9c 59
074f71bb
CM
60def __pick_commit(commit_id, patchname, options):
61 """Pick a commit id.
0618ea9c 62 """
fff9bce5 63 commit = git.Commit(commit_id)
0618ea9c 64
074f71bb
CM
65 if options.name:
66 patchname = options.name
214a8453
CM
67 if patchname:
68 patchname = find_patch_name(patchname, crt_series.patch_exists)
0618ea9c 69
89e3bc51 70 if options.parent:
6972fd6b 71 parent = git_id(crt_series, options.parent)
89e3bc51
YD
72 else:
73 parent = commit.get_parent()
74
0618ea9c 75 if not options.reverse:
89e3bc51 76 bottom = parent
0618ea9c
CM
77 top = commit_id
78 else:
79 bottom = commit_id
89e3bc51 80 top = parent
0618ea9c 81
ba524d4c 82 if options.fold:
27ac2b7e 83 out.start('Folding commit %s' % commit_id)
0618ea9c 84
04b44217 85 # try a direct git apply first
d218d2f8 86 if not git.apply_diff(bottom, top):
fab69eac 87 git.merge_recursive(bottom, git.get_head(), top)
5f9ce587 88
27ac2b7e 89 out.done()
d0bfda1a 90 elif options.update:
e4560d7e
CM
91 rev1 = git_id(crt_series, 'HEAD^')
92 rev2 = git_id(crt_series, 'HEAD')
d0bfda1a
CM
93 files = git.barefiles(rev1, rev2).split('\n')
94
27ac2b7e 95 out.start('Updating with commit %s' % commit_id)
d0bfda1a
CM
96
97 if not git.apply_diff(bottom, top, files = files):
98 raise CmdException, 'Patch updating failed'
99
27ac2b7e 100 out.done()
ba524d4c
CM
101 else:
102 message = commit.get_log()
2ff25eb8
CM
103 if options.expose:
104 message += '(imported from commit %s)\n' % commit.get_id_hash()
ba524d4c
CM
105 author_name, author_email, author_date = \
106 name_email_date(commit.get_author())
107
27ac2b7e 108 out.start('Importing commit %s' % commit_id)
0618ea9c 109
8fce9909
YD
110 newpatch = crt_series.new_patch(patchname, message = message, can_edit = False,
111 unapplied = True, bottom = bottom, top = top,
112 author_name = author_name,
113 author_email = author_email,
114 author_date = author_date)
e2b1102c
CM
115 # in case the patch name was automatically generated
116 patchname = newpatch.get_name()
117
8fce9909 118 # find a patchlog to fork from
e4560d7e
CM
119 refbranchname, refpatchname = parse_rev(patchname)
120 if refpatchname:
8fce9909
YD
121 if refbranchname:
122 # assume the refseries is OK, since we already resolved
123 # commit_str to a git_id
124 refseries = Series(refbranchname)
125 else:
126 refseries = crt_series
127 patch = refseries.get_patch(refpatchname)
128 if patch.get_log():
27ac2b7e
KH
129 out.info("Log was %s" % newpatch.get_log())
130 out.info("Setting log to %s\n" % patch.get_log())
8fce9909 131 newpatch.set_log(patch.get_log())
27ac2b7e 132 out.info("Log is now %s" % newpatch.get_log())
8fce9909 133 else:
27ac2b7e
KH
134 out.info("No log for %s\n" % patchname)
135
7829d19d 136 if not options.unapplied:
2e88afce 137 modified = crt_series.push_patch(patchname)
7829d19d
CM
138 else:
139 modified = False
0618ea9c 140
2e88afce 141 if crt_series.empty_patch(patchname):
27ac2b7e 142 out.done('empty patch')
5f9ce587 143 elif modified:
27ac2b7e 144 out.done('modified')
5f9ce587 145 else:
27ac2b7e
KH
146 out.done()
147
074f71bb
CM
148
149def func(parser, options, args):
150 """Import a commit object as a new patch
151 """
152 if not args:
153 parser.error('incorrect number of arguments')
154
155 if not options.unapplied:
156 check_local_changes()
157 check_conflicts()
158 check_head_top_equal(crt_series)
159
160 if options.ref_branch:
161 remote_series = Series(options.ref_branch)
162 else:
163 remote_series = crt_series
164
165 applied = remote_series.get_applied()
166 unapplied = remote_series.get_unapplied()
167 try:
d3cb28ca 168 patches = parse_patches(args, applied + unapplied, len(applied))
074f71bb
CM
169 commit_id = None
170 except CmdException:
d714caa1 171 if len(args) > 1:
074f71bb
CM
172 raise
173 # no patches found, try a commit id
174 commit_id = git_id(remote_series, args[0])
175
d714caa1 176 if not commit_id and len(patches) > 1:
074f71bb
CM
177 if options.name:
178 raise CmdException, '--name can only be specified with one patch'
179 if options.parent:
180 raise CmdException, '--parent can only be specified with one patch'
181
d37b109f 182 if options.update and not crt_series.get_current():
074f71bb
CM
183 raise CmdException, 'No patches applied'
184
185 if commit_id:
214a8453
CM
186 # Try to guess a patch name if the argument was <branch>:<patch>
187 try:
188 patchname = args[0].split(':')[1]
189 except IndexError:
190 patchname = None
191 __pick_commit(commit_id, patchname, options)
074f71bb
CM
192 else:
193 if options.unapplied:
194 patches.reverse()
195 for patch in patches:
196 __pick_commit(git_id(remote_series, patch), patch, options)
197
6972fd6b 198 print_crt_patch(crt_series)