def absorb(stack, patch_name, temp_name, edit_fun, annotate=None): """Absorb the temp patch into the target patch.""" if annotate: log_msg = 'refresh\n\n' + annotate else: log_msg = 'refresh' trans = transaction.StackTransaction(stack, log_msg) iw = stack.repository.default_iw f = { True: absorb_applied, False: absorb_unapplied }[patch_name in trans.applied] if f(trans, iw, patch_name, temp_name, edit_fun): def info_msg(): pass else: def info_msg(): out.warn( 'The new changes did not apply cleanly to %s.' % patch_name, 'They were saved in %s.' % temp_name) r = trans.run(iw) info_msg() return r
def func(parser, options, args): stack = directory.repository.current_stack iw = stack.repository.default_iw if len(args) >= 1: ref, patches = args[0], args[1:] state = log.get_log_entry( stack.repository, ref, stack.repository.rev_parse(ref) ) elif options.hard: iw.checkout_hard(stack.head.data.tree) return utils.STGIT_SUCCESS else: raise CmdException('Wrong options or number of arguments') trans = transaction.StackTransaction( stack, 'reset', discard_changes=options.hard, allow_bad_head=True, ) try: if patches: log.reset_stack_partially(trans, iw, state, patches) else: log.reset_stack(trans, iw, state) except transaction.TransactionHalted: pass return trans.run(iw, allow_bad_head=not patches)
def __get_published(stack, tree): """Check the patches that were already published.""" trans = transaction.StackTransaction(stack, 'publish') published = trans.check_merged(trans.applied, tree=tree, quiet=True) trans.abort() return published
def func(parser, options, args): """Commit a number of patches.""" stack = directory.repository.current_stack args = common.parse_patches(args, list(stack.patchorder.all_visible)) if len([x for x in [args, options.number is not None, options.all] if x]) > 1: parser.error('too many options') if args: patches = [pn for pn in stack.patchorder.all_visible if pn in args] bad = set(args) - set(patches) if bad: raise common.CmdException('Nonexistent or hidden patch names: %s' % ', '.join(sorted(bad))) elif options.number is not None: if options.number <= len(stack.patchorder.applied): patches = stack.patchorder.applied[:options.number] else: raise common.CmdException('There are not that many applied patches') elif options.all: patches = stack.patchorder.applied else: patches = stack.patchorder.applied[:1] if not patches: raise common.CmdException('No patches to commit') iw = stack.repository.default_iw def allow_conflicts(trans): # As long as the topmost patch stays where it is, it's OK to # run "stg commit" with conflicts in the index. return len(trans.applied) >= 1 trans = transaction.StackTransaction(stack, 'commit', allow_conflicts = allow_conflicts) try: common_prefix = 0 for i in range(min(len(stack.patchorder.applied), len(patches))): if stack.patchorder.applied[i] == patches[i]: common_prefix += 1 else: break if common_prefix < len(patches): to_push = [pn for pn in stack.patchorder.applied[common_prefix:] if pn not in patches[common_prefix:]] # this pops all the applied patches from common_prefix trans.pop_patches(lambda pn: pn in to_push) for pn in patches[common_prefix:]: trans.push_patch(pn, iw) else: to_push = [] new_base = trans.patches[patches[-1]] for pn in patches: trans.patches[pn] = None trans.applied = [pn for pn in trans.applied if pn not in patches] trans.base = new_base out.info('Committed %d patch%s' % (len(patches), ['es', ''][len(patches) == 1])) for pn in to_push: trans.push_patch(pn, iw) except transaction.TransactionHalted: pass return trans.run(iw)
def func(parser, options, args): """Pushes the given patches or the first unapplied onto the stack.""" stack = directory.repository.current_stack iw = stack.repository.default_iw clean_iw = (not options.keep and iw) or None trans = transaction.StackTransaction(stack, 'push', check_clean_iw=clean_iw) if options.number == 0: # explicitly allow this without any warning/error message return if not trans.unapplied: raise CmdException('No patches to push') if options.all: patches = list(trans.unapplied) elif options.number is not None: patches = trans.unapplied[:options.number] elif not args: patches = [trans.unapplied[0]] else: try: patches = parse_patches(args, trans.unapplied) except CmdException as e: try: patches = parse_patches(args, trans.applied) except CmdException: raise e else: raise CmdException( 'Patch%s already applied: %s' % ('es' if len(patches) > 1 else '', ', '.join(patches))) assert patches if options.reverse: patches.reverse() if options.set_tree: for pn in patches: trans.push_tree(pn) else: try: if options.merged: merged = set(trans.check_merged(patches)) else: merged = set() for pn in patches: trans.push_patch(pn, iw, allow_interactive=True, already_merged=pn in merged) except transaction.TransactionHalted: pass return trans.run(iw)
def func(parser, options, args): stack = directory.repository.current_stack if options.number < 1: raise CmdException('Bad number of commands to undo') state = log.undo_state(stack, options.number) trans = transaction.StackTransaction(stack, discard_changes=options.hard) try: log.reset_stack(trans, stack.repository.default_iw, state) except transaction.TransactionHalted: pass return trans.execute('undo %d' % options.number, stack.repository.default_iw, allow_bad_head=True)
def make_temp_patch(stack, patch_name, paths, temp_index): """Commit index to temp patch, in a complete transaction. If any path limiting is in effect, use a temp index.""" tree = write_tree(stack, paths, temp_index) commit = stack.repository.commit(git.CommitData( tree = tree, parents = [stack.head], message = 'Refresh of %s' % patch_name)) temp_name = utils.make_patch_name('refresh-temp', stack.patches.exists) trans = transaction.StackTransaction(stack, 'refresh (create temporary patch)') trans.patches[temp_name] = commit trans.applied.append(temp_name) return trans.run(stack.repository.default_iw, print_current_patch = False), temp_name
def func(parser, options, args): if len(args) != 1: parser.error('incorrect number of arguments') name = args[0] stack = directory.repository.current_stack iw = stack.repository.default_iw check_head_top_equal(stack) if not options.keep: check_index_and_worktree_clean(stack) trans = transaction.StackTransaction(stack) if name not in trans.all_patches: candidates = [pn for pn in trans.all_patches if name in pn] if len(candidates) == 1: name = candidates[0] elif len(candidates) > 1: out.info('Possible patches:\n %s' % '\n '.join(candidates)) raise CmdException('Ambiguous patch name "%s"' % name) elif re.match('[0-9A-Fa-f]{4,40}$', name): sha1 = name name = stack.patches.name_from_sha1(sha1) if not name: raise CmdException('No patch associated with %s' % sha1) else: raise CmdException('Patch "%s" does not exist' % name) if name in trans.applied: to_pop = set(trans.applied[trans.applied.index(name) + 1:]) popped_extra = trans.pop_patches(lambda pn: pn in to_pop) assert not popped_extra elif name in trans.unapplied: try: to_push = trans.unapplied[:trans.unapplied.index(name) + 1] if options.merged: merged = set(trans.check_merged(to_push)) else: merged = set() for pn in to_push: trans.push_patch(pn, iw, allow_interactive=True, already_merged=pn in merged) except transaction.TransactionHalted: pass else: raise CmdException('Cannot goto a hidden patch') return trans.execute('goto', iw)
def _squash(stack, iw, name, msg, save_template, patches, no_verify=False): # If a name was supplied on the command line, make sure it's OK. def bad_name(pn): return pn not in patches and stack.patches.exists(pn) def get_name(cd): return name or utils.make_patch_name(cd.message, bad_name) if name and bad_name(name): raise common.CmdException('Patch name "%s" already taken') def make_squashed_patch(trans, new_commit_data): name = get_name(new_commit_data) trans.patches[name] = stack.repository.commit(new_commit_data) trans.unapplied.insert(0, name) trans = transaction.StackTransaction(stack, 'squash', allow_conflicts=True) push_new_patch = bool(set(patches) & set(trans.applied)) try: new_commit_data = _squash_patches(trans, patches, msg, save_template, no_verify) if new_commit_data: # We were able to construct the squashed commit # automatically. So just delete its constituent patches. to_push = trans.delete_patches(lambda pn: pn in patches) else: # Automatic construction failed. So push the patches # consecutively, so that a second construction attempt is # guaranteed to work. to_push = trans.pop_patches(lambda pn: pn in patches) for pn in patches: trans.push_patch(pn, iw) new_commit_data = _squash_patches(trans, patches, msg, save_template, no_verify) assert not trans.delete_patches(lambda pn: pn in patches) make_squashed_patch(trans, new_commit_data) # Push the new patch if necessary, and any unrelated patches we've # had to pop out of the way. if push_new_patch: trans.push_patch(get_name(new_commit_data), iw) for pn in to_push: trans.push_patch(pn, iw) except SaveTemplateDone: trans.abort(iw) return except transaction.TransactionHalted: pass return trans.run(iw)
def func(parser, options, args): """Reorder patches to make the named patch the topmost one.""" if options.series and args: parser.error('<patches> cannot be used with --series') elif not options.series and not args: parser.error('incorrect number of arguments') stack = directory.repository.current_stack if options.series: if options.series == '-': f = io.open(sys.stdin.fileno()) else: f = io.open(options.series) patches = [] for line in f: patch = re.sub('#.*$', '', line).strip() if patch: patches.append(patch) patches = parse_patches(patches, stack.patchorder.all) else: patches = parse_patches(args, stack.patchorder.all) if not patches: raise CmdException('No patches to float') iw = stack.repository.default_iw check_head_top_equal(stack) if not options.keep and (not options.noapply or any(pn in stack.patchorder.applied for pn in patches)): check_index_and_worktree_clean(stack) trans = transaction.StackTransaction(stack) if options.noapply: applied = [p for p in trans.applied if p not in patches] unapplied = patches + [p for p in trans.unapplied if p not in patches] else: applied = [p for p in trans.applied if p not in patches] + patches unapplied = [p for p in trans.unapplied if p not in patches] try: trans.reorder_patches(applied, unapplied, iw=iw) except transaction.TransactionHalted: pass return trans.execute('float', iw)
def func(parser, options, args): """Sink patches down the stack.""" stack = directory.repository.current_stack if options.to and options.to not in stack.patchorder.applied: raise CmdException('Cannot sink below %s since it is not applied' % options.to) if len(args) > 0: patches = parse_patches(args, stack.patchorder.all) else: # current patch patches = list(stack.patchorder.applied[-1:]) if not patches: raise CmdException('No patches to sink') if options.to and options.to in patches: raise CmdException('Cannot have a sinked patch as target') unapplied_rem = [p for p in stack.patchorder.unapplied if p not in patches] applied_rem = [p for p in stack.patchorder.applied if p not in patches] insert_idx = applied_rem.index(options.to) if options.to else 0 stay_applied, re_applied = applied_rem[:insert_idx], applied_rem[ insert_idx:] if options.nopush: applied = stay_applied + patches unapplied = re_applied + unapplied_rem else: applied = stay_applied + patches + re_applied unapplied = unapplied_rem iw = stack.repository.default_iw check_head_top_equal(stack) if not options.keep: check_index_and_worktree_clean(stack) trans = transaction.StackTransaction(stack) try: trans.reorder_patches(applied, unapplied, iw=iw, allow_interactive=True) except transaction.TransactionHalted: pass return trans.execute('sink', iw)
def _clean(stack, clean_applied, clean_unapplied): trans = transaction.StackTransaction(stack, 'clean', allow_conflicts = True) def del_patch(pn): if pn in stack.patchorder.applied: if pn == stack.patchorder.applied[-1]: # We're about to clean away the topmost patch. Don't # do that if we have conflicts, since that means the # patch is only empty because the conflicts have made # us dump its contents into the index and worktree. if stack.repository.default_index.conflicts(): return False return clean_applied and trans.patches[pn].data.is_nochange() elif pn in stack.patchorder.unapplied: return clean_unapplied and trans.patches[pn].data.is_nochange() for pn in trans.delete_patches(del_patch): trans.push_patch(pn) trans.run()
def func(parser, options, args): """Delete one or more patches.""" stack = directory.repository.get_stack(options.branch) if options.branch: iw = None # can't use index/workdir to manipulate another branch else: iw = stack.repository.default_iw if args and options.top: parser.error('Either --top or patches must be specified') elif args: patches = set( parse_patches( args, list(stack.patchorder.all), len(stack.patchorder.applied) ) ) elif options.top: applied = stack.patchorder.applied if applied: patches = set([applied[-1]]) else: raise CmdException('No patches applied') else: parser.error('No patches specified') if options.spill: if set(stack.patchorder.applied[-len(patches) :]) != patches: parser.error('Can only spill topmost applied patches') iw = None # don't touch index+worktree def allow_conflicts(trans): # Allow conflicts if the topmost patch stays the same. if stack.patchorder.applied: return trans.applied and trans.applied[-1] == stack.patchorder.applied[-1] else: return not trans.applied trans = transaction.StackTransaction( stack, 'delete', allow_conflicts=allow_conflicts ) try: to_push = trans.delete_patches(lambda pn: pn in patches) for pn in to_push: trans.push_patch(pn, iw) except transaction.TransactionHalted: pass return trans.run(iw)
def func(parser, options, args): """Pop the given patches or the topmost one from the stack.""" stack = directory.repository.current_stack iw = stack.repository.default_iw check_head_top_equal(stack) if not options.keep and not options.spill: check_index_and_worktree_clean(stack) trans = transaction.StackTransaction(stack) if options.number == 0: # explicitly allow this without any warning/error message return if not trans.applied: raise CmdException('No patches applied') if options.all: patches = trans.applied elif options.number is not None: # reverse it twice to also work with negative or bigger than # the length numbers patches = trans.applied[::-1][:options.number][::-1] elif not args: patches = [trans.applied[-1]] else: patches = parse_patches(args, trans.applied, ordered=True) if not patches: # FIXME: Why is this an error, and not just a noop ? raise CmdException('No patches to pop') if options.spill: if set(stack.patchorder.applied[-len(patches):]) != set(patches): parser.error('Can only spill topmost applied patches') iw = None # don't touch index+worktree try: trans.reorder_patches( applied=[p for p in trans.applied if p not in patches], unapplied=patches + trans.unapplied, iw=iw, allow_interactive=True, ) except transaction.TransactionException: pass return trans.execute('pop', iw)
def func(parser, options, args): """Create a new patch.""" stack = directory.repository.current_stack if stack.repository.default_index.conflicts(): raise common.CmdException( 'Cannot create a new patch -- resolve conflicts first') # Choose a name for the new patch -- or None, which means make one # up later when we've gotten hold of the commit message. if len(args) == 0: name = None elif len(args) == 1: name = args[0] if stack.patches.exists(name): raise common.CmdException('%s: patch already exists' % name) else: parser.error('incorrect number of arguments') cd = gitlib.CommitData( tree=stack.head.data.tree, parents=[stack.head], message='', author=gitlib.Person.author(), committer=gitlib.Person.committer(), ) cd = common.update_commit_data(cd, options) if options.save_template: options.save_template(cd.message.encode('utf-8')) return utils.STGIT_SUCCESS if not options.no_verify: cd = common.run_commit_msg_hook(stack.repository, cd) if name is None: name = utils.make_patch_name(cd.message, lambda name: stack.patches.exists(name)) # Write the new patch. stack.repository.default_iw trans = transaction.StackTransaction(stack, 'new') trans.patches[name] = stack.repository.commit(cd) trans.applied.append(name) return trans.run()
def func(parser, options, args): """Unhide a range of patch in the series.""" stack = directory.repository.current_stack trans = transaction.StackTransaction(stack, 'unhide') if not args: parser.error('No patches specified') patches = parse_patches(args, trans.all_patches) for p in patches: if p not in trans.hidden: raise CmdException('Patch "%s" not hidden' % p) applied = list(trans.applied) unapplied = trans.unapplied + patches hidden = [p for p in trans.hidden if p not in set(patches)] trans.reorder_patches(applied, unapplied, hidden) return trans.run()
def func(parser, options, args): """Reorder patches to make the named patch the topmost one. """ if options.series and args: parser.error('<patches> cannot be used with --series') elif not options.series and not args: parser.error('incorrect number of arguments') stack = directory.repository.current_stack if options.series: if options.series == '-': f = io.open(sys.stdin.fileno()) else: f = io.open(options.series) patches = [] for line in f: patch = re.sub('#.*$', '', line).strip() if patch: patches.append(patch) else: patches = common.parse_patches(args, stack.patchorder.all) if not patches: raise common.CmdException('No patches to float') applied = [p for p in stack.patchorder.applied if p not in patches] + \ patches unapplied = [p for p in stack.patchorder.unapplied if p not in patches] iw = stack.repository.default_iw clean_iw = (not options.keep and iw) or None trans = transaction.StackTransaction(stack, 'float', check_clean_iw=clean_iw) try: trans.reorder_patches(applied, unapplied, iw=iw) except transaction.TransactionHalted: pass return trans.run(iw)
def func(parser, options, args): """Sink patches down the stack. """ stack = directory.repository.current_stack if options.to and options.to not in stack.patchorder.applied: raise common.CmdException( 'Cannot sink below %s since it is not applied' % options.to ) if len(args) > 0: patches = common.parse_patches(args, stack.patchorder.all) else: # current patch patches = list(stack.patchorder.applied[-1:]) if not patches: raise common.CmdException('No patches to sink') if options.to and options.to in patches: raise common.CmdException('Cannot have a sinked patch as target') applied = [p for p in stack.patchorder.applied if p not in patches] if options.to: insert_idx = applied.index(options.to) else: insert_idx = 0 applied = applied[:insert_idx] + patches + applied[insert_idx:] unapplied = [p for p in stack.patchorder.unapplied if p not in patches] iw = stack.repository.default_iw clean_iw = (not options.keep and iw) or None trans = transaction.StackTransaction( stack, 'sink', check_clean_iw=clean_iw ) try: trans.reorder_patches( applied, unapplied, iw=iw, allow_interactive=True ) except transaction.TransactionHalted: pass return trans.run(iw)
def func(parser, options, args): """Hide a range of patch in the series.""" stack = directory.repository.current_stack trans = transaction.StackTransaction(stack, 'hide') if not args: parser.error('No patches specified') patches = common.parse_patches(args, trans.all_patches) for p in patches: if p in trans.hidden: out.warn('Patch "%s" already hidden' % p) patches = [p for p in patches if p not in set(trans.hidden)] applied = [p for p in trans.applied if p not in set(patches)] unapplied = [p for p in trans.unapplied if p not in set(patches)] hidden = patches + trans.hidden trans.reorder_patches(applied, unapplied, hidden) return trans.run()
def func(parser, options, args): if len(args) != 1: parser.error('incorrect number of arguments') patch = args[0] stack = directory.repository.current_stack iw = stack.repository.default_iw clean_iw = (not options.keep and iw) or None trans = transaction.StackTransaction(stack, 'goto', check_clean_iw=clean_iw) if patch not in trans.all_patches: candidate = get_patch_from_list(patch, trans.all_patches) if candidate is None: raise CmdException('Patch "%s" does not exist' % patch) patch = candidate if patch in trans.applied: to_pop = set(trans.applied[trans.applied.index(patch) + 1:]) popped_extra = trans.pop_patches(lambda pn: pn in to_pop) assert not popped_extra elif patch in trans.unapplied: try: to_push = trans.unapplied[:trans.unapplied.index(patch) + 1] if options.merged: merged = set(trans.check_merged(to_push)) else: merged = set() for pn in to_push: trans.push_patch(pn, iw, allow_interactive=True, already_merged=pn in merged) except transaction.TransactionHalted: pass else: raise CmdException('Cannot goto a hidden patch') return trans.run(iw)
def perform_edit( stack, cd, orig_patchname, new_patchname, edit_diff, diff_flags, set_tree=None, ): """Given instructions, performs required the edit. :returns: 2-tuple: - the result of the transaction - the new patch name, whether changed or not. """ # Refresh the committer information cd = cd.set_committer(None) # Rewrite the StGit patch with the given diff (and any patches on top of # it). iw = stack.repository.default_iw common.check_head_top_equal(stack) trans = transaction.StackTransaction(stack, allow_conflicts=True) if orig_patchname in trans.applied: popped = trans.applied[trans.applied.index(orig_patchname) + 1:] popped_extra = trans.pop_patches(lambda pn: pn in popped) assert not popped_extra else: popped = [] trans.patches[orig_patchname] = stack.repository.commit(cd) if new_patchname == "": new_patchname = stack.patches.make_name(cd.message_str, allow=orig_patchname) if new_patchname is not None and orig_patchname != new_patchname: out.start('Renaming patch "%s" to "%s"' % (orig_patchname, new_patchname)) trans.rename_patch(orig_patchname, new_patchname) out.done() log_stack_state(stack, 'rename %s to %s' % (orig_patchname, new_patchname)) else: new_patchname = orig_patchname try: for pn in popped: if set_tree: trans.push_tree(pn) else: trans.push_patch(pn, iw, allow_interactive=True) except transaction.TransactionHalted: pass try: # Either a complete success, or a conflict during push. But in # either case, we've successfully effected the edits the user # asked us for. return trans.execute('edit', iw), new_patchname except transaction.TransactionException: # Transaction aborted -- we couldn't check out files due to # dirty index/worktree. The edits were not carried out. note_patch_application_failure( get_patch_description(stack.repository, cd, orig_patchname, edit_diff, diff_flags)) return utils.STGIT_COMMAND_ERROR, new_patchname
def func(parser, options, args): """Pushes the given patches or the first unapplied onto the stack.""" stack = directory.repository.current_stack iw = stack.repository.default_iw if options.number == 0: # explicitly allow this without any warning/error message return if not stack.patchorder.unapplied: raise CmdException('No patches to push') if options.all: if options.noapply: raise CmdException('Cannot use --noapply with --all') patches = list(stack.patchorder.unapplied) elif options.number is not None: if options.noapply: raise CmdException('Cannot use --noapply with --number') patches = list(stack.patchorder.unapplied[: options.number]) elif not args: if options.noapply: raise CmdException('Must supply patch names with --noapply') patches = [stack.patchorder.unapplied[0]] else: try: patches = parse_patches(args, stack.patchorder.unapplied) except CmdException as e: try: patches = parse_patches(args, stack.patchorder.applied) except CmdException: raise e else: raise CmdException( 'Patch%s already applied: %s' % ('es' if len(patches) > 1 else '', ', '.join(patches)) ) assert patches check_head_top_equal(stack) if not options.keep and not options.noapply: check_index_and_worktree_clean(stack) trans = transaction.StackTransaction(stack) if options.reverse: patches.reverse() if options.set_tree: if options.noapply: raise CmdException('Cannot use --noapply with --set-tree') for pn in patches: trans.push_tree(pn) elif options.noapply: if options.merged: raise CmdException('Cannot use --noapply with --merged') unapplied = patches + [pn for pn in trans.unapplied if pn not in patches] trans.reorder_patches(trans.applied, unapplied) else: try: if options.merged: merged = set(trans.check_merged(patches)) else: merged = set() for pn in patches: trans.push_patch( pn, iw, allow_interactive=True, already_merged=pn in merged ) except transaction.TransactionHalted: pass return trans.execute('push', iw)
def func(parser, options, args): """Uncommit a number of patches. """ stack = directory.repository.current_stack if options.to: if options.number: parser.error('cannot give both --to and --number') if len(args) != 0: parser.error('cannot specify patch name with --to') patch_nr = patchnames = None to_commit = stack.repository.rev_parse(options.to) # check whether the --to commit is on a different branch merge_bases = directory.repository.get_merge_bases( to_commit, stack.base ) if to_commit not in merge_bases: to_commit = merge_bases[0] options.exclusive = True elif options.number: if options.number <= 0: parser.error('invalid value passed to --number') patch_nr = options.number if len(args) == 0: patchnames = None elif len(args) == 1: # prefix specified patchnames = ['%s%d' % (args[0], i) for i in range(patch_nr, 0, -1)] else: parser.error('when using --number, specify at most one patch name') elif len(args) == 0: patchnames = None patch_nr = 1 else: patchnames = args patch_nr = len(patchnames) def check_and_append(c, n): next = n.data.parents try: [next] = next except ValueError: out.done() raise CmdException( 'Trying to uncommit %s, which does not have exactly one parent' % n.sha1) return c.append(n) commits = [] next_commit = stack.base if patch_nr: out.start('Uncommitting %d patches' % patch_nr) for i in range(patch_nr): check_and_append(commits, next_commit) next_commit = next_commit.data.parent else: if options.exclusive: out.start('Uncommitting to %s (exclusive)' % to_commit.sha1) else: out.start('Uncommitting to %s' % to_commit.sha1) while True: if next_commit == to_commit: if not options.exclusive: check_and_append(commits, next_commit) break check_and_append(commits, next_commit) next_commit = next_commit.data.parent patch_nr = len(commits) taken_names = set(stack.patchorder.all) if patchnames: for pn in patchnames: if pn in taken_names: raise CmdException('Patch name "%s" already taken' % pn) taken_names.add(pn) else: patchnames = [] for c in reversed(commits): pn = utils.make_patch_name(c.data.message, lambda pn: pn in taken_names) patchnames.append(pn) taken_names.add(pn) patchnames.reverse() trans = transaction.StackTransaction(stack, 'uncommit', allow_conflicts=True, allow_bad_head=True) for commit, pn in zip(commits, patchnames): trans.patches[pn] = commit trans.applied = list(reversed(patchnames)) + trans.applied trans.run(set_head=False) out.done()
def func(parser, options, args): """Edit the given patch or the current one. """ stack = directory.repository.current_stack if len(args) == 0: if not stack.patchorder.applied: raise CmdException( 'Cannot edit top patch, because no patches are applied') patchname = stack.patchorder.applied[-1] elif len(args) == 1: [patchname] = args if not stack.patches.exists(patchname): raise CmdException('%s: no such patch' % patchname) else: parser.error('Cannot edit more than one patch') cd = orig_cd = stack.patches.get(patchname).commit.data if options.set_tree: cd = cd.set_tree( stack.repository.rev_parse(options.set_tree, discard_stderr=True, object_type='tree')) cd = edit.auto_edit_patch( stack.repository, cd, msg=(None if options.message is None else options.message.encode( config.get('i18n.commitencoding'))), author=options.author, sign_str=options.sign_str, ) if options.save_template: options.save_template( edit.patch_desc( stack.repository, cd, options.diff, options.diff_flags, replacement_diff=None, )) return utils.STGIT_SUCCESS use_editor = cd == orig_cd or options.edit or options.diff if use_editor: cd, failed_diff = edit.interactive_edit_patch(stack.repository, cd, options.diff, options.diff_flags) else: failed_diff = None def failed(reason='Edited patch did not apply.'): fn = '.stgit-failed.patch' with io.open(fn, 'wb') as f: f.write( edit.patch_desc( stack.repository, cd, options.diff, options.diff_flags, replacement_diff=failed_diff, )) out.error(reason, 'The patch has been saved to "%s".' % fn) return utils.STGIT_COMMAND_ERROR # If we couldn't apply the patch, fail without even trying to # effect any of the changes. if failed_diff: return failed() if not options.no_verify and (use_editor or cd.message != orig_cd.message): try: cd = run_commit_msg_hook(stack.repository, cd, use_editor) except Exception: if options.diff: failed('The commit-msg hook failed.') raise # Refresh the committer information cd = cd.set_committer(None) # The patch applied, so now we have to rewrite the StGit patch # (and any patches on top of it). iw = stack.repository.default_iw trans = transaction.StackTransaction(stack, 'edit', allow_conflicts=True) if patchname in trans.applied: popped = trans.applied[trans.applied.index(patchname) + 1:] popped_extra = trans.pop_patches(lambda pn: pn in popped) assert not popped_extra else: popped = [] trans.patches[patchname] = stack.repository.commit(cd) try: for pn in popped: if options.set_tree: trans.push_tree(pn) else: trans.push_patch(pn, iw, allow_interactive=True) except transaction.TransactionHalted: pass try: # Either a complete success, or a conflict during push. But in # either case, we've successfully effected the edits the user # asked us for. return trans.run(iw) except transaction.TransactionException: # Transaction aborted -- we couldn't check out files due to # dirty index/worktree. The edits were not carried out. return failed()