1#!/usr/bin/env python 2# Copyright 2014 The Chromium Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6"""Change the upstream of the current branch.""" 7 8from __future__ import print_function 9 10import argparse 11import sys 12 13import subprocess2 14 15from git_common import upstream, current_branch, run, tags, set_branch_config 16from git_common import get_or_create_merge_base, root, manual_merge_base 17from git_common import get_branch_tree, topo_iter 18 19import git_rebase_update 20 21def main(args): 22 root_ref = root() 23 24 parser = argparse.ArgumentParser() 25 g = parser.add_mutually_exclusive_group() 26 g.add_argument('new_parent', nargs='?', 27 help='New parent branch (or tag) to reparent to.') 28 g.add_argument('--root', action='store_true', 29 help='Reparent to the configured root branch (%s).' % root_ref) 30 g.add_argument('--lkgr', action='store_true', 31 help='Reparent to the lkgr tag.') 32 opts = parser.parse_args(args) 33 34 # TODO(iannucci): Allow specification of the branch-to-reparent 35 36 branch = current_branch() 37 38 if opts.root: 39 new_parent = root_ref 40 elif opts.lkgr: 41 new_parent = 'lkgr' 42 else: 43 if not opts.new_parent: 44 parser.error('Must specify new parent somehow') 45 new_parent = opts.new_parent 46 cur_parent = upstream(branch) 47 48 if branch == 'HEAD' or not branch: 49 parser.error('Must be on the branch you want to reparent') 50 if new_parent == cur_parent: 51 parser.error('Cannot reparent a branch to its existing parent') 52 53 if not cur_parent: 54 msg = ( 55 "Unable to determine %s@{upstream}.\n\nThis can happen if you didn't use " 56 "`git new-branch` to create the branch and haven't used " 57 "`git branch --set-upstream-to` to assign it one.\n\nPlease assign an " 58 "upstream branch and then run this command again." 59 ) 60 print(msg % branch, file=sys.stderr) 61 return 1 62 63 mbase = get_or_create_merge_base(branch, cur_parent) 64 65 all_tags = tags() 66 if cur_parent in all_tags: 67 cur_parent += ' [tag]' 68 69 try: 70 run('show-ref', new_parent) 71 except subprocess2.CalledProcessError: 72 print('fatal: invalid reference: %s' % new_parent, file=sys.stderr) 73 return 1 74 75 if new_parent in all_tags: 76 print("Reparenting %s to track %s [tag] (was %s)" % (branch, new_parent, 77 cur_parent)) 78 set_branch_config(branch, 'remote', '.') 79 set_branch_config(branch, 'merge', new_parent) 80 else: 81 print("Reparenting %s to track %s (was %s)" % (branch, new_parent, 82 cur_parent)) 83 run('branch', '--set-upstream-to', new_parent, branch) 84 85 manual_merge_base(branch, mbase, new_parent) 86 87 # ONLY rebase-update the branch which moved (and dependants) 88 _, branch_tree = get_branch_tree() 89 branches = [branch] 90 for branch, parent in topo_iter(branch_tree): 91 if parent in branches: 92 branches.append(branch) 93 return git_rebase_update.main(['--no-fetch'] + branches) 94 95 96if __name__ == '__main__': # pragma: no cover 97 try: 98 sys.exit(main(sys.argv[1:])) 99 except KeyboardInterrupt: 100 sys.stderr.write('interrupted\n') 101 sys.exit(1) 102