blob: 3366a3ec3b409db507a608a3db162229f5c055ca [file] [log] [blame]
Josip Sokcevic4de5dea2022-03-23 21:15:14 +00001#!/usr/bin/env python3
iannucci@chromium.orgc050a5b2014-03-26 06:18:50 +00002# 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.
iannucci@chromium.orgc050a5b2014-03-26 06:18:50 +00005"""Change the upstream of the current branch."""
6
7import argparse
8import sys
9
10import subprocess2
11
12from git_common import upstream, current_branch, run, tags, set_branch_config
iannucci@chromium.org10fbe872014-05-16 22:31:13 +000013from git_common import get_or_create_merge_base, root, manual_merge_base
Henrique Ferreiro9f273d02019-02-22 10:10:27 +000014from git_common import get_branch_tree, topo_iter
iannucci@chromium.orgc050a5b2014-03-26 06:18:50 +000015
16import git_rebase_update
Anthony Polito87e73892021-07-09 19:15:11 +000017import metrics
iannucci@chromium.orgc050a5b2014-03-26 06:18:50 +000018
Mike Frysinger124bb8e2023-09-06 05:48:55 +000019
Anthony Polito87e73892021-07-09 19:15:11 +000020@metrics.collector.collect_metrics('git reparent-branch')
iannucci@chromium.orgc050a5b2014-03-26 06:18:50 +000021def main(args):
Mike Frysinger124bb8e2023-09-06 05:48:55 +000022 root_ref = root()
iannucci@chromium.orgc050a5b2014-03-26 06:18:50 +000023
Mike Frysinger124bb8e2023-09-06 05:48:55 +000024 parser = argparse.ArgumentParser()
25 g = parser.add_mutually_exclusive_group()
26 g.add_argument('new_parent',
27 nargs='?',
28 help='New parent branch (or tag) to reparent to.')
29 g.add_argument('--root',
30 action='store_true',
31 help='Reparent to the configured root branch (%s).' %
32 root_ref)
33 g.add_argument('--lkgr',
34 action='store_true',
35 help='Reparent to the lkgr tag.')
36 opts = parser.parse_args(args)
iannucci@chromium.orgc050a5b2014-03-26 06:18:50 +000037
Mike Frysinger124bb8e2023-09-06 05:48:55 +000038 # TODO(iannucci): Allow specification of the branch-to-reparent
iannucci@chromium.orgc050a5b2014-03-26 06:18:50 +000039
Mike Frysinger124bb8e2023-09-06 05:48:55 +000040 branch = current_branch()
iannucci@chromium.orgf3e37a02015-12-04 19:03:23 +000041
Mike Frysinger124bb8e2023-09-06 05:48:55 +000042 if opts.root:
43 new_parent = root_ref
44 elif opts.lkgr:
45 new_parent = 'lkgr'
46 else:
47 if not opts.new_parent:
48 parser.error('Must specify new parent somehow')
49 new_parent = opts.new_parent
50 cur_parent = upstream(branch)
iannucci@chromium.orgc050a5b2014-03-26 06:18:50 +000051
Mike Frysinger124bb8e2023-09-06 05:48:55 +000052 if branch == 'HEAD' or not branch:
53 parser.error('Must be on the branch you want to reparent')
54 if new_parent == cur_parent:
55 parser.error('Cannot reparent a branch to its existing parent')
iannucci@chromium.orgc050a5b2014-03-26 06:18:50 +000056
Mike Frysinger124bb8e2023-09-06 05:48:55 +000057 if not cur_parent:
58 msg = (
59 "Unable to determine %s@{upstream}.\n\nThis can happen if you "
60 "didn't use `git new-branch` to create the branch and haven't used "
61 "`git branch --set-upstream-to` to assign it one.\n\nPlease assign "
62 "an upstream branch and then run this command again.")
63 print(msg % branch, file=sys.stderr)
64 return 1
iannucci@chromium.orgf3e37a02015-12-04 19:03:23 +000065
Mike Frysinger124bb8e2023-09-06 05:48:55 +000066 mbase = get_or_create_merge_base(branch, cur_parent)
iannucci@chromium.orgc050a5b2014-03-26 06:18:50 +000067
Mike Frysinger124bb8e2023-09-06 05:48:55 +000068 all_tags = tags()
69 if cur_parent in all_tags:
70 cur_parent += ' [tag]'
iannucci@chromium.orgc050a5b2014-03-26 06:18:50 +000071
Mike Frysinger124bb8e2023-09-06 05:48:55 +000072 try:
73 run('show-ref', new_parent)
74 except subprocess2.CalledProcessError:
75 print('fatal: invalid reference: %s' % new_parent, file=sys.stderr)
76 return 1
iannucci@chromium.orgc050a5b2014-03-26 06:18:50 +000077
Mike Frysinger124bb8e2023-09-06 05:48:55 +000078 if new_parent in all_tags:
79 print("Reparenting %s to track %s [tag] (was %s)" %
80 (branch, new_parent, cur_parent))
81 set_branch_config(branch, 'remote', '.')
82 set_branch_config(branch, 'merge', new_parent)
83 else:
84 print("Reparenting %s to track %s (was %s)" %
85 (branch, new_parent, cur_parent))
86 run('branch', '--set-upstream-to', new_parent, branch)
iannucci@chromium.orgc050a5b2014-03-26 06:18:50 +000087
Mike Frysinger124bb8e2023-09-06 05:48:55 +000088 manual_merge_base(branch, mbase, new_parent)
iannucci@chromium.org10fbe872014-05-16 22:31:13 +000089
Mike Frysinger124bb8e2023-09-06 05:48:55 +000090 # ONLY rebase-update the branch which moved (and dependants)
91 _, branch_tree = get_branch_tree()
92 branches = [branch]
93 for branch, parent in topo_iter(branch_tree):
94 if parent in branches:
95 branches.append(branch)
96 return git_rebase_update.main(['--no-fetch', '--keep-empty'] + branches)
iannucci@chromium.orgc050a5b2014-03-26 06:18:50 +000097
98
99if __name__ == '__main__': # pragma: no cover
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000100 try:
101 with metrics.collector.print_notice_and_exit():
102 sys.exit(main(sys.argv[1:]))
103 except KeyboardInterrupt:
104 sys.stderr.write('interrupted\n')
105 sys.exit(1)