Mercurial > hg
comparison hgext/histedit.py @ 17407:31c123a2f273
histedit: factored out diff/patch logic
This patch is the first step towards a refactoring of the histedit
extension to use underlying graft machinery instead of diff/patch as
discussed in issue3527. Replacing diff/patch with graft is necessary
to fix, for example, issue3582.
author | Leah Xue <leahxue@fb.com> |
---|---|
date | Tue, 21 Aug 2012 16:06:34 -0700 |
parents | 96189d60d810 |
children | 8e1fa8a32f2b |
comparison
equal
deleted
inserted
replaced
17406:fc14953e8e34 | 17407:31c123a2f273 |
---|---|
173 # d, drop = remove commit from history | 173 # d, drop = remove commit from history |
174 # m, mess = edit message without changing commit content | 174 # m, mess = edit message without changing commit content |
175 # | 175 # |
176 """) | 176 """) |
177 | 177 |
178 def foldchanges(ui, repo, node1, node2, opts): | |
179 """Produce a new changeset that represents the diff from node1 to node2.""" | |
180 try: | |
181 fd, patchfile = tempfile.mkstemp(prefix='hg-histedit-') | |
182 fp = os.fdopen(fd, 'w') | |
183 diffopts = patch.diffopts(ui, opts) | |
184 diffopts.git = True | |
185 diffopts.ignorews = False | |
186 diffopts.ignorewsamount = False | |
187 diffopts.ignoreblanklines = False | |
188 gen = patch.diff(repo, node1, node2, opts=diffopts) | |
189 for chunk in gen: | |
190 fp.write(chunk) | |
191 fp.close() | |
192 files = set() | |
193 patch.patch(ui, repo, patchfile, files=files, eolmode=None) | |
194 finally: | |
195 os.unlink(patchfile) | |
196 return files | |
197 | |
178 def between(repo, old, new, keep): | 198 def between(repo, old, new, keep): |
179 revs = [old] | 199 revs = [old] |
180 current = old | 200 current = old |
181 while current != new: | 201 while current != new: |
182 ctx = repo[current] | 202 ctx = repo[current] |
198 oldctx = repo[ha] | 218 oldctx = repo[ha] |
199 if oldctx.parents()[0] == ctx: | 219 if oldctx.parents()[0] == ctx: |
200 ui.debug('node %s unchanged\n' % ha) | 220 ui.debug('node %s unchanged\n' % ha) |
201 return oldctx, [], [], [] | 221 return oldctx, [], [], [] |
202 hg.update(repo, ctx.node()) | 222 hg.update(repo, ctx.node()) |
203 fd, patchfile = tempfile.mkstemp(prefix='hg-histedit-') | |
204 fp = os.fdopen(fd, 'w') | |
205 diffopts = patch.diffopts(ui, opts) | |
206 diffopts.git = True | |
207 diffopts.ignorews = False | |
208 diffopts.ignorewsamount = False | |
209 diffopts.ignoreblanklines = False | |
210 gen = patch.diff(repo, oldctx.parents()[0].node(), ha, opts=diffopts) | |
211 for chunk in gen: | |
212 fp.write(chunk) | |
213 fp.close() | |
214 try: | 223 try: |
215 files = set() | 224 files = foldchanges(ui, repo, oldctx.p1().node() , ha, opts) |
216 try: | 225 if not files: |
217 patch.patch(ui, repo, patchfile, files=files, eolmode=None) | 226 ui.warn(_('%s: empty changeset') |
218 if not files: | 227 % node.hex(ha)) |
219 ui.warn(_('%s: empty changeset') | 228 return ctx, [], [], [] |
220 % node.hex(ha)) | |
221 return ctx, [], [], [] | |
222 finally: | |
223 os.unlink(patchfile) | |
224 except Exception: | 229 except Exception: |
225 raise util.Abort(_('Fix up the change and run ' | 230 raise util.Abort(_('Fix up the change and run ' |
226 'hg histedit --continue')) | 231 'hg histedit --continue')) |
227 n = repo.commit(text=oldctx.description(), user=oldctx.user(), | 232 n = repo.commit(text=oldctx.description(), user=oldctx.user(), |
228 date=oldctx.date(), extra=oldctx.extra()) | 233 date=oldctx.date(), extra=oldctx.extra()) |
230 | 235 |
231 | 236 |
232 def edit(ui, repo, ctx, ha, opts): | 237 def edit(ui, repo, ctx, ha, opts): |
233 oldctx = repo[ha] | 238 oldctx = repo[ha] |
234 hg.update(repo, ctx.node()) | 239 hg.update(repo, ctx.node()) |
235 fd, patchfile = tempfile.mkstemp(prefix='hg-histedit-') | |
236 fp = os.fdopen(fd, 'w') | |
237 diffopts = patch.diffopts(ui, opts) | |
238 diffopts.git = True | |
239 diffopts.ignorews = False | |
240 diffopts.ignorewsamount = False | |
241 diffopts.ignoreblanklines = False | |
242 gen = patch.diff(repo, oldctx.parents()[0].node(), ha, opts=diffopts) | |
243 for chunk in gen: | |
244 fp.write(chunk) | |
245 fp.close() | |
246 try: | 240 try: |
247 files = set() | 241 files = foldchanges(ui, repo, oldctx.p1().node() , ha, opts) |
248 try: | |
249 patch.patch(ui, repo, patchfile, files=files, eolmode=None) | |
250 finally: | |
251 os.unlink(patchfile) | |
252 except Exception: | 242 except Exception: |
253 pass | 243 pass |
254 raise util.Abort(_('Make changes as needed, you may commit or record as ' | 244 raise util.Abort(_('Make changes as needed, you may commit or record as ' |
255 'needed now.\nWhen you are finished, run hg' | 245 'needed now.\nWhen you are finished, run hg' |
256 ' histedit --continue to resume.')) | 246 ' histedit --continue to resume.')) |
257 | 247 |
258 def fold(ui, repo, ctx, ha, opts): | 248 def fold(ui, repo, ctx, ha, opts): |
259 oldctx = repo[ha] | 249 oldctx = repo[ha] |
260 hg.update(repo, ctx.node()) | 250 hg.update(repo, ctx.node()) |
261 fd, patchfile = tempfile.mkstemp(prefix='hg-histedit-') | |
262 fp = os.fdopen(fd, 'w') | |
263 diffopts = patch.diffopts(ui, opts) | |
264 diffopts.git = True | |
265 diffopts.ignorews = False | |
266 diffopts.ignorewsamount = False | |
267 diffopts.ignoreblanklines = False | |
268 gen = patch.diff(repo, oldctx.parents()[0].node(), ha, opts=diffopts) | |
269 for chunk in gen: | |
270 fp.write(chunk) | |
271 fp.close() | |
272 try: | 251 try: |
273 files = set() | 252 files = foldchanges(ui, repo, oldctx.p1().node() , ha, opts) |
274 try: | 253 if not files: |
275 patch.patch(ui, repo, patchfile, files=files, eolmode=None) | 254 ui.warn(_('%s: empty changeset') |
276 if not files: | 255 % node.hex(ha)) |
277 ui.warn(_('%s: empty changeset') | 256 return ctx, [], [], [] |
278 % node.hex(ha)) | |
279 return ctx, [], [], [] | |
280 finally: | |
281 os.unlink(patchfile) | |
282 except Exception: | 257 except Exception: |
283 raise util.Abort(_('Fix up the change and run ' | 258 raise util.Abort(_('Fix up the change and run ' |
284 'hg histedit --continue')) | 259 'hg histedit --continue')) |
285 n = repo.commit(text='fold-temp-revision %s' % ha, user=oldctx.user(), | 260 n = repo.commit(text='fold-temp-revision %s' % ha, user=oldctx.user(), |
286 date=oldctx.date(), extra=oldctx.extra()) | 261 date=oldctx.date(), extra=oldctx.extra()) |
287 return finishfold(ui, repo, ctx, oldctx, n, opts, []) | 262 return finishfold(ui, repo, ctx, oldctx, n, opts, []) |
288 | 263 |
289 def finishfold(ui, repo, ctx, oldctx, newnode, opts, internalchanges): | 264 def finishfold(ui, repo, ctx, oldctx, newnode, opts, internalchanges): |
290 parent = ctx.parents()[0].node() | 265 parent = ctx.parents()[0].node() |
291 hg.update(repo, parent) | 266 hg.update(repo, parent) |
292 fd, patchfile = tempfile.mkstemp(prefix='hg-histedit-') | 267 files = foldchanges(ui, repo, parent, newnode, opts) |
293 fp = os.fdopen(fd, 'w') | |
294 diffopts = patch.diffopts(ui, opts) | |
295 diffopts.git = True | |
296 diffopts.ignorews = False | |
297 diffopts.ignorewsamount = False | |
298 diffopts.ignoreblanklines = False | |
299 gen = patch.diff(repo, parent, newnode, opts=diffopts) | |
300 for chunk in gen: | |
301 fp.write(chunk) | |
302 fp.close() | |
303 files = set() | |
304 try: | |
305 patch.patch(ui, repo, patchfile, files=files, eolmode=None) | |
306 finally: | |
307 os.unlink(patchfile) | |
308 newmessage = '\n***\n'.join( | 268 newmessage = '\n***\n'.join( |
309 [ctx.description()] + | 269 [ctx.description()] + |
310 [repo[r].description() for r in internalchanges] + | 270 [repo[r].description() for r in internalchanges] + |
311 [oldctx.description()]) + '\n' | 271 [oldctx.description()]) + '\n' |
312 # If the changesets are from the same author, keep it. | 272 # If the changesets are from the same author, keep it. |
324 | 284 |
325 | 285 |
326 def message(ui, repo, ctx, ha, opts): | 286 def message(ui, repo, ctx, ha, opts): |
327 oldctx = repo[ha] | 287 oldctx = repo[ha] |
328 hg.update(repo, ctx.node()) | 288 hg.update(repo, ctx.node()) |
329 fd, patchfile = tempfile.mkstemp(prefix='hg-histedit-') | |
330 fp = os.fdopen(fd, 'w') | |
331 diffopts = patch.diffopts(ui, opts) | |
332 diffopts.git = True | |
333 diffopts.ignorews = False | |
334 diffopts.ignorewsamount = False | |
335 diffopts.ignoreblanklines = False | |
336 gen = patch.diff(repo, oldctx.parents()[0].node(), ha, opts=diffopts) | |
337 for chunk in gen: | |
338 fp.write(chunk) | |
339 fp.close() | |
340 try: | 289 try: |
341 files = set() | 290 files = foldchanges(ui, repo, oldctx.p1().node() , ha, opts) |
342 try: | |
343 patch.patch(ui, repo, patchfile, files=files, eolmode=None) | |
344 finally: | |
345 os.unlink(patchfile) | |
346 except Exception: | 291 except Exception: |
347 raise util.Abort(_('Fix up the change and run ' | 292 raise util.Abort(_('Fix up the change and run ' |
348 'hg histedit --continue')) | 293 'hg histedit --continue')) |
349 message = oldctx.description() + '\n' | 294 message = oldctx.description() + '\n' |
350 message = ui.edit(message, ui.username()) | 295 message = ui.edit(message, ui.username()) |