def remove_empty_branches(branch_tree): tag_set = git.tags() ensure_root_checkout = git.once(lambda: git.run("checkout", git.root())) deletions = set() downstreams = collections.defaultdict(list) for branch, parent in git.topo_iter(branch_tree, top_down=False): downstreams[parent].append(branch) if git.hash_one(branch) == git.hash_one(parent): ensure_root_checkout() logging.debug("branch %s merged to %s", branch, parent) for down in downstreams[branch]: if down in deletions: continue if parent in tag_set: git.set_branch_config(down, "remote", ".") git.set_branch_config(down, "merge", "refs/tags/%s" % parent) print ("Reparented %s to track %s [tag] (was tracking %s)" % (down, parent, branch)) else: git.run("branch", "--set-upstream-to", parent, down) print ("Reparented %s to track %s (was tracking %s)" % (down, parent, branch)) deletions.add(branch) print git.run("branch", "-d", branch)
def remove_empty_branches(branch_tree): tag_set = git.tags() ensure_root_checkout = git.once(lambda: git.run('checkout', git.root())) deletions = set() downstreams = collections.defaultdict(list) for branch, parent in git.topo_iter(branch_tree, top_down=False): downstreams[parent].append(branch) if git.hash_one(branch) == git.hash_one(parent): ensure_root_checkout() logging.debug('branch %s merged to %s', branch, parent) for down in downstreams[branch]: if down in deletions: continue if parent in tag_set: git.set_branch_config(down, 'remote', '.') git.set_branch_config(down, 'merge', 'refs/tags/%s' % parent) print('Reparented %s to track %s [tag] (was tracking %s)' % (down, parent, branch)) else: git.run('branch', '--set-upstream-to', parent, down) print('Reparented %s to track %s (was tracking %s)' % (down, parent, branch)) deletions.add(branch) print git.run('branch', '-d', branch)
def main(args): current = current_branch() if current == 'HEAD': current = None old_name_help = 'The old branch to rename.' if current: old_name_help += ' (default %(default)r)' parser = argparse.ArgumentParser() parser.add_argument('old_name', nargs=('?' if current else 1), help=old_name_help, default=current) parser.add_argument('new_name', help='The new branch name.') opts = parser.parse_args(args) # when nargs=1, we get a list :( if isinstance(opts.old_name, list): opts.old_name = opts.old_name[0] try: run('branch', '-m', opts.old_name, opts.new_name) # update the downstreams for branch, merge in branch_config_map('merge').items(): if merge == 'refs/heads/' + opts.old_name: # Only care about local branches if branch_config(branch, 'remote') == '.': set_branch_config(branch, 'merge', 'refs/heads/' + opts.new_name) except subprocess2.CalledProcessError as cpe: sys.stderr.write(cpe.stderr) return 1 return 0
def main(args): current = current_branch() if current == 'HEAD': current = None old_name_help = 'The old branch to rename.' if current: old_name_help += ' (default %(default)r)' parser = argparse.ArgumentParser() parser.add_argument('old_name', nargs=('?' if current else 1), help=old_name_help, default=current) parser.add_argument('new_name', help='The new branch name.') opts = parser.parse_args(args) # when nargs=1, we get a list :( if isinstance(opts.old_name, list): opts.old_name = opts.old_name[0] try: run('branch', '-m', opts.old_name, opts.new_name) # update the downstreams for branch, merge in branch_config_map('merge').iteritems(): if merge == 'refs/heads/' + opts.old_name: # Only care about local branches if branch_config(branch, 'remote') == '.': set_branch_config(branch, 'merge', 'refs/heads/' + opts.new_name) except subprocess2.CalledProcessError as cpe: sys.stderr.write(cpe.stderr) return 1
def main(args): root_ref = root() parser = argparse.ArgumentParser() g = parser.add_mutually_exclusive_group() g.add_argument('new_parent', nargs='?', help='New parent branch (or tag) to reparent to.') g.add_argument('--root', action='store_true', help='Reparent to the configured root branch (%s).' % root_ref) g.add_argument('--lkgr', action='store_true', help='Reparent to the lkgr tag.') opts = parser.parse_args(args) # TODO(iannucci): Allow specification of the branch-to-reparent branch = current_branch() if opts.root: new_parent = root_ref elif opts.lkgr: new_parent = 'lkgr' else: new_parent = opts.new_parent cur_parent = upstream(branch) if branch == 'HEAD' or not branch: parser.error('Must be on the branch you want to reparent') if new_parent == cur_parent: parser.error('Cannot reparent a branch to its existing parent') mbase = get_or_create_merge_base(branch, cur_parent) all_tags = tags() if cur_parent in all_tags: cur_parent += ' [tag]' try: run('show-ref', new_parent) except subprocess2.CalledProcessError: print >> sys.stderr, 'fatal: invalid reference: %s' % new_parent return 1 if new_parent in all_tags: print("Reparenting %s to track %s [tag] (was %s)" % (branch, new_parent, cur_parent)) set_branch_config(branch, 'remote', '.') set_branch_config(branch, 'merge', new_parent) else: print("Reparenting %s to track %s (was %s)" % (branch, new_parent, cur_parent)) run('branch', '--set-upstream-to', new_parent, branch) manual_merge_base(branch, mbase, new_parent) # TODO(iannucci): ONLY rebase-update the branch which moved (and dependants) return git_rebase_update.main(['--no-fetch'])
def main(args): root_ref = root() parser = argparse.ArgumentParser() g = parser.add_mutually_exclusive_group() g.add_argument('new_parent', nargs='?', help='New parent branch (or tag) to reparent to.') g.add_argument('--root', action='store_true', help='Reparent to the configured root branch (%s).' % root_ref) g.add_argument('--lkgr', action='store_true', help='Reparent to the lkgr tag.') opts = parser.parse_args(args) # TODO(iannucci): Allow specification of the branch-to-reparent branch = current_branch() if opts.root: new_parent = root_ref elif opts.lkgr: new_parent = 'lkgr' else: if not opts.new_parent: parser.error('Must specify new parent somehow') new_parent = opts.new_parent cur_parent = upstream(branch) if branch == 'HEAD' or not branch: parser.error('Must be on the branch you want to reparent') if new_parent == cur_parent: parser.error('Cannot reparent a branch to its existing parent') mbase = get_or_create_merge_base(branch, cur_parent) all_tags = tags() if cur_parent in all_tags: cur_parent += ' [tag]' try: run('show-ref', new_parent) except subprocess2.CalledProcessError: print >> sys.stderr, 'fatal: invalid reference: %s' % new_parent return 1 if new_parent in all_tags: print ("Reparenting %s to track %s [tag] (was %s)" % (branch, new_parent, cur_parent)) set_branch_config(branch, 'remote', '.') set_branch_config(branch, 'merge', new_parent) else: print ("Reparenting %s to track %s (was %s)" % (branch, new_parent, cur_parent)) run('branch', '--set-upstream-to', new_parent, branch) manual_merge_base(branch, mbase, new_parent) # TODO(iannucci): ONLY rebase-update the branch which moved (and dependants) return git_rebase_update.main(['--no-fetch'])
def remove_empty_branches(branch_tree): tag_set = git.tags() ensure_root_checkout = git.once(lambda: git.run('checkout', git.root())) deletions = {} reparents = {} downstreams = collections.defaultdict(list) for branch, parent in git.topo_iter(branch_tree, top_down=False): if git.is_dormant(branch): continue downstreams[parent].append(branch) # If branch and parent have the same tree, then branch has to be marked # for deletion and its children and grand-children reparented to parent. if git.hash_one(branch + ":") == git.hash_one(parent + ":"): ensure_root_checkout() logging.debug('branch %s merged to %s', branch, parent) # Mark branch for deletion while remembering the ordering, then add all # its children as grand-children of its parent and record reparenting # information if necessary. deletions[branch] = len(deletions) for down in downstreams[branch]: if down in deletions: continue # Record the new and old parent for down, or update such a record # if it already exists. Keep track of the ordering so that reparenting # happen in topological order. downstreams[parent].append(down) if down not in reparents: reparents[down] = (len(reparents), parent, branch) else: order, _, old_parent = reparents[down] reparents[down] = (order, parent, old_parent) # Apply all reparenting recorded, in order. for branch, value in sorted(reparents.items(), key=lambda x: x[1][0]): _, parent, old_parent = value if parent in tag_set: git.set_branch_config(branch, 'remote', '.') git.set_branch_config(branch, 'merge', 'refs/tags/%s' % parent) print('Reparented %s to track %s [tag] (was tracking %s)' % (branch, parent, old_parent)) else: git.run('branch', '--set-upstream-to', parent, branch) print('Reparented %s to track %s (was tracking %s)' % (branch, parent, old_parent)) # Apply all deletions recorded, in order. for branch, _ in sorted(deletions.items(), key=lambda x: x[1]): print(git.run('branch', '-d', branch))
def remove_empty_branches(branch_tree): tag_set = git.tags() ensure_root_checkout = git.once(lambda: git.run('checkout', git.root())) deletions = {} reparents = {} downstreams = collections.defaultdict(list) for branch, parent in git.topo_iter(branch_tree, top_down=False): downstreams[parent].append(branch) # If branch and parent have the same tree, then branch has to be marked # for deletion and its children and grand-children reparented to parent. if git.hash_one(branch+":") == git.hash_one(parent+":"): ensure_root_checkout() logging.debug('branch %s merged to %s', branch, parent) # Mark branch for deletion while remembering the ordering, then add all # its children as grand-children of its parent and record reparenting # information if necessary. deletions[branch] = len(deletions) for down in downstreams[branch]: if down in deletions: continue # Record the new and old parent for down, or update such a record # if it already exists. Keep track of the ordering so that reparenting # happen in topological order. downstreams[parent].append(down) if down not in reparents: reparents[down] = (len(reparents), parent, branch) else: order, _, old_parent = reparents[down] reparents[down] = (order, parent, old_parent) # Apply all reparenting recorded, in order. for branch, value in sorted(reparents.iteritems(), key=lambda x:x[1][0]): _, parent, old_parent = value if parent in tag_set: git.set_branch_config(branch, 'remote', '.') git.set_branch_config(branch, 'merge', 'refs/tags/%s' % parent) print ('Reparented %s to track %s [tag] (was tracking %s)' % (branch, parent, old_parent)) else: git.run('branch', '--set-upstream-to', parent, branch) print ('Reparented %s to track %s (was tracking %s)' % (branch, parent, old_parent)) # Apply all deletions recorded, in order. for branch, _ in sorted(deletions.iteritems(), key=lambda x: x[1]): print git.run('branch', '-d', branch)
def main(args): root_ref = root() parser = argparse.ArgumentParser() g = parser.add_mutually_exclusive_group() g.add_argument('new_parent', nargs='?', help='New parent branch (or tag) to reparent to.') g.add_argument('--root', action='store_true', help='Reparent to the configured root branch (%s).' % root_ref) g.add_argument('--lkgr', action='store_true', help='Reparent to the lkgr tag.') opts = parser.parse_args(args) # TODO(iannucci): Allow specification of the branch-to-reparent branch = current_branch() if opts.root: new_parent = root_ref elif opts.lkgr: new_parent = 'lkgr' else: if not opts.new_parent: parser.error('Must specify new parent somehow') new_parent = opts.new_parent cur_parent = upstream(branch) if branch == 'HEAD' or not branch: parser.error('Must be on the branch you want to reparent') if new_parent == cur_parent: parser.error('Cannot reparent a branch to its existing parent') if not cur_parent: msg = ( "Unable to determine %s@{upstream}.\n\nThis can happen if you didn't use " "`git new-branch` to create the branch and haven't used " "`git branch --set-upstream-to` to assign it one.\n\nPlease assign an " "upstream branch and then run this command again." ) print(msg % branch, file=sys.stderr) return 1 mbase = get_or_create_merge_base(branch, cur_parent) all_tags = tags() if cur_parent in all_tags: cur_parent += ' [tag]' try: run('show-ref', new_parent) except subprocess2.CalledProcessError: print('fatal: invalid reference: %s' % new_parent, file=sys.stderr) return 1 if new_parent in all_tags: print("Reparenting %s to track %s [tag] (was %s)" % (branch, new_parent, cur_parent)) set_branch_config(branch, 'remote', '.') set_branch_config(branch, 'merge', new_parent) else: print("Reparenting %s to track %s (was %s)" % (branch, new_parent, cur_parent)) run('branch', '--set-upstream-to', new_parent, branch) manual_merge_base(branch, mbase, new_parent) # ONLY rebase-update the branch which moved (and dependants) _, branch_tree = get_branch_tree() branches = [branch] for branch, parent in topo_iter(branch_tree): if parent in branches: branches.append(branch) return git_rebase_update.main(['--no-fetch'] + branches)