def start(self): self.__branches_info = get_branches_info( include_tracking_status=self.verbosity >= 1) roots = set() # A map of parents to a list of their children. for branch, branch_info in self.__branches_info.iteritems(): if not branch_info: continue parent = branch_info.upstream if parent and not self.__branches_info[parent]: branch_upstream = upstream(branch) # If git can't find the upstream, mark the upstream as gone. if branch_upstream: parent = branch_upstream else: self.__gone_branches.add(parent) # A parent that isn't in the branches info is a root. roots.add(parent) self.__parent_map[parent].append(branch) self.__current_branch = current_branch() self.__current_hash = hash_one('HEAD', short=True) self.__tag_set = tags() if roots: for root in sorted(roots): self.__append_branch(root) else: no_branches = OutputLine() no_branches.append('No User Branches') self.output.append(no_branches)
def main(args): default_args = git.config_list('depot-tools.upstream-diff.default-args') args = default_args + args parser = argparse.ArgumentParser() parser.add_argument('--wordwise', action='store_true', default=False, help=('Print a colorized wordwise diff ' 'instead of line-wise diff')) opts, extra_args = parser.parse_known_args(args) cur = git.current_branch() if not cur or cur == 'HEAD': print 'fatal: Cannot perform git-upstream-diff while not on a branch' return 1 par = git.upstream(cur) if not par: print 'fatal: No upstream configured for branch \'%s\'' % cur return 1 cmd = [git.GIT_EXE, 'diff', '--patience', '-C', '-C'] if opts.wordwise: cmd += ['--word-diff=color', r'--word-diff-regex=(\w+|[^[:space:]])'] cmd += [git.get_or_create_merge_base(cur, par)] cmd += extra_args subprocess2.check_call(cmd)
def main(args): default_args = git.config_list('depot-tools.upstream-diff.default-args') args = default_args + args parser = argparse.ArgumentParser() parser.add_argument('--wordwise', action='store_true', default=False, help=( 'Print a colorized wordwise diff ' 'instead of line-wise diff')) opts, extra_args = parser.parse_known_args(args) cur = git.current_branch() if not cur or cur == 'HEAD': print 'fatal: Cannot perform git-upstream-diff while not on a branch' return 1 par = git.upstream(cur) if not par: print 'fatal: No upstream configured for branch \'%s\'' % cur return 1 cmd = [git.GIT_EXE, 'diff', '--patience', '-C', '-C'] if opts.wordwise: cmd += ['--word-diff=color', r'--word-diff-regex=(\w+|[^[:space:]])'] cmd += [git.get_or_create_merge_base(cur, par)] cmd += extra_args return subprocess2.check_call(cmd)
def start(self): self.__branches_info = get_branches_info( include_tracking_status=self.verbosity >= 1) roots = set() # A map of parents to a list of their children. for branch, branch_info in self.__branches_info.iteritems(): if not branch_info: continue parent = branch_info.upstream if not self.__branches_info[parent]: branch_upstream = upstream(branch) # If git can't find the upstream, mark the upstream as gone. if branch_upstream: parent = branch_upstream else: self.__gone_branches.add(parent) # A parent that isn't in the branches info is a root. roots.add(parent) self.__parent_map[parent].append(branch) self.__current_branch = current_branch() self.__current_hash = hash_one('HEAD', short=True) self.__tag_set = tags() if roots: for root in sorted(roots): self.__append_branch(root) else: no_branches = OutputLine() no_branches.append('No User Branches') self.output.append(no_branches)
def main(argv): colorama.init() assert len(argv) == 1, "No arguments expected" branch_map = {} par_map = collections.defaultdict(list) for branch in branches(): par = upstream(branch) or NO_UPSTREAM branch_map[branch] = par par_map[par].append(branch) current = current_branch() hashes = hash_multi(current, *branch_map.keys()) current_hash = hashes[0] par_hashes = { k: hashes[i + 1] for i, k in enumerate(branch_map.iterkeys()) } par_hashes[NO_UPSTREAM] = 0 tag_set = tags() while par_map: for parent in par_map: if parent not in branch_map: if parent not in par_hashes: par_hashes[parent] = hash_one(parent) print_branch(current, current_hash, parent, par_hashes, par_map, branch_map, tag_set) break
def main(args): parser = argparse.ArgumentParser( formatter_class=argparse.ArgumentDefaultsHelpFormatter, description=__doc__, ) parser.add_argument('branch_name') g = parser.add_mutually_exclusive_group() g.add_argument('--upstream-current', '--upstream_current', action='store_true', help='set upstream branch to current branch.') g.add_argument('--upstream', metavar='REF', default=root(), help='upstream branch (or tag) to track.') g.add_argument('--inject-current', '--inject_current', action='store_true', help='new branch adopts current branch\'s upstream,' + ' and new branch becomes current branch\'s upstream.') g.add_argument('--lkgr', action='store_const', const='lkgr', dest='upstream', help='set basis ref for new branch to lkgr.') opts = parser.parse_args(args) try: if opts.inject_current: below = current_branch() if below is None: raise Exception('no current branch') above = upstream(below) if above is None: raise Exception('branch %s has no upstream' % (below)) run('checkout', '--track', above, '-b', opts.branch_name) run('branch', '--set-upstream-to', opts.branch_name, below) elif opts.upstream_current: run('checkout', '--track', '-b', opts.branch_name) else: if opts.upstream in tags(): # TODO(iannucci): ensure that basis_ref is an ancestor of HEAD? run('checkout', '--no-track', '-b', opts.branch_name, hash_one(opts.upstream)) set_config('branch.%s.remote' % opts.branch_name, '.') set_config('branch.%s.merge' % opts.branch_name, opts.upstream) else: # TODO(iannucci): Detect unclean workdir then stash+pop if we need to # teleport to a conflicting portion of history? run('checkout', '--track', opts.upstream, '-b', opts.branch_name) get_or_create_merge_base(opts.branch_name) except subprocess2.CalledProcessError as cpe: sys.stdout.write(cpe.stdout) sys.stderr.write(cpe.stderr) return 1 sys.stderr.write('Switched to branch %s.\n' % opts.branch_name) return 0
def SplitCl(description_file, comment_file, changelist, cmd_upload): """"Splits a branch into smaller branches and uploads CLs. Args: description_file: File containing the description of uploaded CLs. comment_file: File containing the comment of uploaded CLs. changelist: The Changelist class. cmd_upload: The function associated with the git cl upload command. Returns: 0 in case of success. 1 in case of error. """ description = AddUploadedByGitClSplitToDescription( ReadFile(description_file)) comment = ReadFile(comment_file) if comment_file else None try: EnsureInGitRepository() cl = changelist() change = cl.GetChange(cl.GetCommonAncestorWithUpstream(), None) files = change.AffectedFiles() if not files: print 'Cannot split an empty CL.' return 1 author = git.run('config', 'user.email').strip() or None refactor_branch = git.current_branch() assert refactor_branch, "Can't run from detached branch." refactor_branch_upstream = git.upstream(refactor_branch) assert refactor_branch_upstream, \ "Branch %s must have an upstream." % refactor_branch owners_database = owners.Database(change.RepositoryRoot(), file, os.path) owners_database.load_data_needed_for([f.LocalPath() for f in files]) files_split_by_owners = GetFilesSplitByOwners(owners_database, files) print('Will split current branch (' + refactor_branch + ') in ' + str(len(files_split_by_owners)) + ' CLs.\n') for directory, files in files_split_by_owners.iteritems(): # Use '/' as a path separator in the branch name and the CL description # and comment. directory = directory.replace(os.path.sep, '/') # Upload the CL. UploadCl(refactor_branch, refactor_branch_upstream, directory, files, author, description, comment, owners_database, changelist, cmd_upload) # Go back to the original branch. git.run('checkout', refactor_branch) except subprocess2.CalledProcessError as cpe: sys.stderr.write(cpe.stderr) return 1 return 0
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 start(self): self.__branches_info = get_branches_info( include_tracking_status=self.verbosity >= 1) if (self.verbosity >= 2): # Avoid heavy import unless necessary. from git_cl import get_cl_statuses, color_for_status, Changelist change_cls = [ Changelist(branchref='refs/heads/' + b) for b in self.__branches_info.keys() if b ] status_info = get_cl_statuses(change_cls, fine_grained=self.verbosity > 2, max_processes=self.maxjobs) # This is a blocking get which waits for the remote CL status to be # retrieved. for cl, status in status_info: self.__status_info[cl.GetBranch()] = (cl.GetIssueURL(), color_for_status(status), status) roots = set() # A map of parents to a list of their children. for branch, branch_info in self.__branches_info.items(): if not branch_info: continue parent = branch_info.upstream if self.__check_cycle(branch): continue if not self.__branches_info[parent]: branch_upstream = upstream(branch) # If git can't find the upstream, mark the upstream as gone. if branch_upstream: parent = branch_upstream else: self.__gone_branches.add(parent) # A parent that isn't in the branches info is a root. roots.add(parent) self.__parent_map[parent].append(branch) self.__current_branch = current_branch() self.__current_hash = hash_one('HEAD', short=True) self.__tag_set = tags() if roots: for root in sorted(roots): self.__append_branch(root) else: no_branches = OutputLine() no_branches.append('No User Branches') self.output.append(no_branches)
def start(self): self.__branches_info = get_branches_info( include_tracking_status=self.verbosity >= 1) if (self.verbosity >= 2): # Avoid heavy import unless necessary. from git_cl import get_cl_statuses, color_for_status, Changelist change_cls = [Changelist(branchref='refs/heads/'+b) for b in self.__branches_info.keys() if b] status_info = get_cl_statuses(change_cls, fine_grained=self.verbosity > 2, max_processes=self.maxjobs) # This is a blocking get which waits for the remote CL status to be # retrieved. for cl, status in status_info: self.__status_info[cl.GetBranch()] = (cl.GetIssueURL(), color_for_status(status), status) roots = set() # A map of parents to a list of their children. for branch, branch_info in self.__branches_info.iteritems(): if not branch_info: continue parent = branch_info.upstream if not self.__branches_info[parent]: branch_upstream = upstream(branch) # If git can't find the upstream, mark the upstream as gone. if branch_upstream: parent = branch_upstream else: self.__gone_branches.add(parent) # A parent that isn't in the branches info is a root. roots.add(parent) self.__parent_map[parent].append(branch) self.__current_branch = current_branch() self.__current_hash = hash_one('HEAD', short=True) self.__tag_set = tags() if roots: for root in sorted(roots): self.__append_branch(root) else: no_branches = OutputLine() no_branches.append('No User Branches') self.output.append(no_branches)
def start(self): self.__branches_info = get_branches_info( include_tracking_status=self.verbosity >= 1) if (self.verbosity >= 2): # Avoid heavy import unless necessary. from git_cl import get_cl_statuses status_info = get_cl_statuses(self.__branches_info.keys(), fine_grained=self.verbosity > 2, max_processes=self.maxjobs) for _ in xrange(len(self.__branches_info)): # This is a blocking get which waits for the remote CL status to be # retrieved. (branch, url, color) = status_info.next() self.__status_info[branch] = (url, color) roots = set() # A map of parents to a list of their children. for branch, branch_info in self.__branches_info.iteritems(): if not branch_info: continue parent = branch_info.upstream if not self.__branches_info[parent]: branch_upstream = upstream(branch) # If git can't find the upstream, mark the upstream as gone. if branch_upstream: parent = branch_upstream else: self.__gone_branches.add(parent) # A parent that isn't in the branches info is a root. roots.add(parent) self.__parent_map[parent].append(branch) self.__current_branch = current_branch() self.__current_hash = hash_one('HEAD', short=True) self.__tag_set = tags() if roots: for root in sorted(roots): self.__append_branch(root) else: no_branches = OutputLine() no_branches.append('No User Branches') self.output.append(no_branches)
def main(args): default_args = git.get_config_list( 'depot-tools.upstream-diff.default-args') args = default_args + args current_branch = git.current_branch() parser = argparse.ArgumentParser() parser.add_argument('--wordwise', action='store_true', default=False, help=('Print a colorized wordwise diff ' 'instead of line-wise diff')) parser.add_argument('--branch', default=current_branch, help='Show changes from a different branch. Passing ' '"HEAD" is the same as omitting this option (it ' 'diffs against the current branch)') opts, extra_args = parser.parse_known_args(args) if opts.branch == 'HEAD': opts.branch = current_branch if not opts.branch or opts.branch == 'HEAD': print('fatal: Cannot perform git-upstream-diff while not on a branch') return 1 par = git.upstream(opts.branch) if not par: print('fatal: No upstream configured for branch \'%s\'' % opts.branch) return 1 cmd = [ git.GIT_EXE, '-c', 'core.quotePath=false', 'diff', '--patience', '-C', '-C' ] if opts.wordwise: cmd += ['--word-diff=color', r'--word-diff-regex=(\w+|[^[:space:]])'] cmd += [git.get_or_create_merge_base(opts.branch, par)] # Only specify the end commit if it is not the current branch, this lets the # diff include uncommitted changes when diffing the current branch. if opts.branch != current_branch: cmd += [opts.branch] cmd += extra_args return subprocess2.check_call(cmd)
def main(argv): parser = argparse.ArgumentParser( description=__doc__.strip().splitlines()[0], epilog=' '.join(__doc__.strip().splitlines()[1:])) g = parser.add_mutually_exclusive_group() g.add_argument( 'merge_base', nargs='?', help='The new hash to use as the merge base for the current branch') g.add_argument('--delete', '-d', action='store_true', help='Remove the set mark.') opts = parser.parse_args(argv) cur = current_branch() if opts.delete: try: remove_merge_base(cur) except CalledProcessError: print "No merge base currently exists for %s." % cur return 0 if opts.merge_base: try: opts.merge_base = hash_one(opts.merge_base) except CalledProcessError: print >> sys.stderr, ('fatal: could not resolve %s as a commit' % (opts.merge_base)) return 1 manual_merge_base(cur, opts.merge_base, upstream(cur)) ret = 0 actual = get_or_create_merge_base(cur) if opts.merge_base and opts.merge_base != actual: ret = 1 print "Invalid merge_base %s" % opts.merge_base print "merge_base(%s): %s" % (cur, actual) return ret
def main(argv): parser = argparse.ArgumentParser( description=__doc__.strip().splitlines()[0], epilog=' '.join(__doc__.strip().splitlines()[1:])) g = parser.add_mutually_exclusive_group() g.add_argument( 'merge_base', nargs='?', help='The new hash to use as the merge base for the current branch' ) g.add_argument('--delete', '-d', action='store_true', help='Remove the set mark.') opts = parser.parse_args(argv) cur = current_branch() if opts.delete: try: remove_merge_base(cur) except CalledProcessError: print "No merge base currently exists for %s." % cur return 0 if opts.merge_base: try: opts.merge_base = hash_one(opts.merge_base) except CalledProcessError: print >> sys.stderr, ( 'fatal: could not resolve %s as a commit' % (opts.merge_base) ) return 1 manual_merge_base(cur, opts.merge_base, upstream(cur)) ret = 0 actual = get_or_create_merge_base(cur) if opts.merge_base and opts.merge_base != actual: ret = 1 print "Invalid merge_base %s" % opts.merge_base print "merge_base(%s): %s" % (cur, actual) return ret
def main(args): default_args = git.get_config_list('depot-tools.upstream-diff.default-args') args = default_args + args current_branch = git.current_branch() parser = argparse.ArgumentParser() parser.add_argument('--wordwise', action='store_true', default=False, help=( 'Print a colorized wordwise diff ' 'instead of line-wise diff')) parser.add_argument('--branch', default=current_branch, help='Show changes from a different branch. Passing ' '"HEAD" is the same as omitting this option (it ' 'diffs against the current branch)') opts, extra_args = parser.parse_known_args(args) if opts.branch == 'HEAD': opts.branch = current_branch if not opts.branch or opts.branch == 'HEAD': print 'fatal: Cannot perform git-upstream-diff while not on a branch' return 1 par = git.upstream(opts.branch) if not par: print 'fatal: No upstream configured for branch \'%s\'' % opts.branch return 1 cmd = [git.GIT_EXE, '-c', 'core.quotePath=false', 'diff', '--patience', '-C', '-C'] if opts.wordwise: cmd += ['--word-diff=color', r'--word-diff-regex=(\w+|[^[:space:]])'] cmd += [git.get_or_create_merge_base(opts.branch, par)] # Only specify the end commit if it is not the current branch, this lets the # diff include uncommitted changes when diffing the current branch. if opts.branch != current_branch: cmd += [opts.branch] cmd += extra_args return subprocess2.check_call(cmd)
def create_new_branch(branch_name, upstream_current=False, upstream=None, inject_current=False): upstream = upstream or git_common.root() try: if inject_current: below = git_common.current_branch() if below is None: raise Exception('no current branch') above = git_common.upstream(below) if above is None: raise Exception('branch %s has no upstream' % (below)) git_common.run('checkout', '--track', above, '-b', branch_name) git_common.run('branch', '--set-upstream-to', branch_name, below) elif upstream_current: git_common.run('checkout', '--track', '-b', branch_name) else: if upstream in git_common.tags(): # TODO(iannucci): ensure that basis_ref is an ancestor of HEAD? git_common.run('checkout', '--no-track', '-b', branch_name, git_common.hash_one(upstream)) git_common.set_config('branch.%s.remote' % branch_name, '.') git_common.set_config('branch.%s.merge' % branch_name, upstream) else: # TODO(iannucci): Detect unclean workdir then stash+pop if we need to # teleport to a conflicting portion of history? git_common.run('checkout', '--track', upstream, '-b', branch_name) git_common.get_or_create_merge_base(branch_name) except subprocess2.CalledProcessError as cpe: sys.stdout.write(cpe.stdout.decode('utf-8', 'replace')) sys.stderr.write(cpe.stderr.decode('utf-8', 'replace')) return 1 sys.stderr.write('Switched to branch %s.\n' % branch_name) return 0
def main(argv): colorama.init() assert len(argv) == 1, "No arguments expected" branch_map = {} par_map = collections.defaultdict(list) for branch in branches(): par = upstream(branch) or NO_UPSTREAM branch_map[branch] = par par_map[par].append(branch) current = current_branch() hashes = hash_multi(current, *branch_map.keys()) current_hash = hashes[0] par_hashes = {k: hashes[i+1] for i, k in enumerate(branch_map.iterkeys())} par_hashes[NO_UPSTREAM] = 0 tag_set = tags() while par_map: for parent in par_map: if parent not in branch_map: if parent not in par_hashes: par_hashes[parent] = hash_one(parent) print_branch(current, current_hash, parent, par_hashes, par_map, branch_map, tag_set) break
def _upfn(b): parent = upstream(b) if parent: return hash_one(parent)
def SplitCl(description_file, comment_file, changelist, cmd_upload, dry_run, cq_dry_run, enable_auto_submit, repository_root): """"Splits a branch into smaller branches and uploads CLs. Args: description_file: File containing the description of uploaded CLs. comment_file: File containing the comment of uploaded CLs. changelist: The Changelist class. cmd_upload: The function associated with the git cl upload command. dry_run: Whether this is a dry run (no branches or CLs created). cq_dry_run: If CL uploads should also do a cq dry run. enable_auto_submit: If CL uploads should also enable auto submit. Returns: 0 in case of success. 1 in case of error. """ description = AddUploadedByGitClSplitToDescription( ReadFile(description_file)) comment = ReadFile(comment_file) if comment_file else None try: EnsureInGitRepository() cl = changelist() upstream = cl.GetCommonAncestorWithUpstream() files = [ (action.strip(), f) for action, f in scm.GIT.CaptureStatus(repository_root, upstream) ] if not files: print('Cannot split an empty CL.') return 1 author = git.run('config', 'user.email').strip() or None refactor_branch = git.current_branch() assert refactor_branch, "Can't run from detached branch." refactor_branch_upstream = git.upstream(refactor_branch) assert refactor_branch_upstream, \ "Branch %s must have an upstream." % refactor_branch owners_database = owners.Database(repository_root, open, os.path) owners_database.load_data_needed_for([f for _, f in files]) files_split_by_owners = GetFilesSplitByOwners(owners_database, files) num_cls = len(files_split_by_owners) print('Will split current branch (' + refactor_branch + ') into ' + str(num_cls) + ' CLs.\n') if cq_dry_run and num_cls > CL_SPLIT_FORCE_LIMIT: print( 'This will generate "%r" CLs. This many CLs can potentially generate' ' too much load on the build infrastructure. Please email' ' [email protected] to ensure that this won\'t break anything.' ' The infra team reserves the right to cancel your jobs if they are' ' overloading the CQ.' % num_cls) answer = raw_input('Proceed? (y/n):') if answer.lower() != 'y': return 0 for cl_index, (directory, files) in \ enumerate(files_split_by_owners.items(), 1): # Use '/' as a path separator in the branch name and the CL description # and comment. directory = directory.replace(os.path.sep, '/') file_paths = [f for _, f in files] reviewers = owners_database.reviewers_for(file_paths, author) if dry_run: PrintClInfo(cl_index, num_cls, directory, file_paths, description, reviewers) else: UploadCl(refactor_branch, refactor_branch_upstream, directory, files, description, comment, reviewers, changelist, cmd_upload, cq_dry_run, enable_auto_submit, repository_root) # Go back to the original branch. git.run('checkout', refactor_branch) except subprocess2.CalledProcessError as cpe: sys.stderr.write(cpe.stderr) return 1 return 0
def SplitCl(description_file, comment_file, changelist, cmd_upload, dry_run, cq_dry_run): """"Splits a branch into smaller branches and uploads CLs. Args: description_file: File containing the description of uploaded CLs. comment_file: File containing the comment of uploaded CLs. changelist: The Changelist class. cmd_upload: The function associated with the git cl upload command. dry_run: Whether this is a dry run (no branches or CLs created). cq_dry_run: If CL uploads should also do a cq dry run. Returns: 0 in case of success. 1 in case of error. """ description = AddUploadedByGitClSplitToDescription(ReadFile(description_file)) comment = ReadFile(comment_file) if comment_file else None try: EnsureInGitRepository() cl = changelist() change = cl.GetChange(cl.GetCommonAncestorWithUpstream(), None) files = change.AffectedFiles() if not files: print 'Cannot split an empty CL.' return 1 author = git.run('config', 'user.email').strip() or None refactor_branch = git.current_branch() assert refactor_branch, "Can't run from detached branch." refactor_branch_upstream = git.upstream(refactor_branch) assert refactor_branch_upstream, \ "Branch %s must have an upstream." % refactor_branch owners_database = owners.Database(change.RepositoryRoot(), file, os.path) owners_database.load_data_needed_for([f.LocalPath() for f in files]) files_split_by_owners = GetFilesSplitByOwners(owners_database, files) num_cls = len(files_split_by_owners) print('Will split current branch (' + refactor_branch + ') into ' + str(num_cls) + ' CLs.\n') if cq_dry_run and num_cls > CL_SPLIT_FORCE_LIMIT: print ( 'This will generate "%r" CLs. This many CLs can potentially generate' ' too much load on the build infrastructure. Please email' ' [email protected] to ensure that this won\'t break anything.' ' The infra team reserves the right to cancel your jobs if they are' ' overloading the CQ.') % num_cls answer = raw_input('Proceed? (y/n):') if answer.lower() != 'y': return 0 for cl_index, (directory, files) in \ enumerate(files_split_by_owners.iteritems(), 1): # Use '/' as a path separator in the branch name and the CL description # and comment. directory = directory.replace(os.path.sep, '/') file_paths = [f.LocalPath() for f in files] reviewers = owners_database.reviewers_for(file_paths, author) if dry_run: PrintClInfo(cl_index, num_cls, directory, file_paths, description, reviewers) else: UploadCl(refactor_branch, refactor_branch_upstream, directory, files, description, comment, reviewers, changelist, cmd_upload, cq_dry_run) # Go back to the original branch. git.run('checkout', refactor_branch) except subprocess2.CalledProcessError as cpe: sys.stderr.write(cpe.stderr) return 1 return 0
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)