def main(args): parser = argparse.ArgumentParser( formatter_class=argparse.ArgumentDefaultsHelpFormatter ) parser.add_argument('branch_name') g = parser.add_mutually_exclusive_group() g.add_argument('--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('--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.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
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 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') 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) # TODO(iannucci): ONLY rebase-update the branch which moved (and dependants) return git_rebase_update.main(['--no_fetch'])
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 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): """Runs cpplint on the current changelist.""" """Adapted from git_cl.py CMDlint """ parser = git_cl.OptionParser() parser.add_option('--filter', action='append', metavar='-x,+y', help='Comma-separated list of cpplint\'s category-filters') parser.add_option('--project_root') parser.add_option('--base_branch') auth.add_auth_options(parser) options, args = parser.parse_args(args) auth_config = auth.extract_auth_config_from_options(options) # Access to a protected member _XX of a client class # pylint: disable=protected-access try: import cpplint import cpplint_chromium except ImportError: print('Your depot_tools is missing cpplint.py and/or cpplint_chromium.py.') return 1 # Change the current working directory before calling lint so that it # shows the correct base. settings = git_cl.settings previous_cwd = os.getcwd() os.chdir(settings.GetRoot()) try: cl = git_cl.Changelist(auth_config=auth_config) change = cl.GetChange(git_common.get_or_create_merge_base(cl.GetBranch(), options.base_branch), None) files = [f.LocalPath() for f in change.AffectedFiles()] if not files: print('Cannot lint an empty CL') return 0 # Process cpplints arguments if any. command = args + files if options.filter: command = ['--filter=' + ','.join(options.filter)] + command if options.project_root: command = ['--project_root=' + options.project_root] + command filenames = cpplint.ParseArguments(command) white_regex = re.compile(settings.GetLintRegex()) black_regex = re.compile(settings.GetLintIgnoreRegex()) extra_check_functions = [cpplint_chromium.CheckPointerDeclarationWhitespace] for filename in filenames: if white_regex.match(filename): if black_regex.match(filename): print('Ignoring file %s' % filename) else: cpplint.ProcessFile(filename, cpplint._cpplint_state.verbose_level, extra_check_functions) else: print('Skipping file %s' % filename) finally: os.chdir(previous_cwd) print('Total errors found: %d\n' % cpplint._cpplint_state.error_count) if cpplint._cpplint_state.error_count != 0: return 1 return 0
def main(argv, outbuf): if '-h' in argv or '--help' in argv: _print_help(outbuf) return 0 map_extra = git_common.get_config_list('depot_tools.map_extra') cmd = [ git_common.GIT_EXE, 'log', git_common.root(), '--graph', '--branches', '--tags', '--color=always', '--date=short', '--pretty=format:%H%x00%D%x00%cd%x00%s' ] + map_extra + argv log_proc = subprocess2.Popen(cmd, stdout=subprocess2.PIPE, shell=False) current = git_common.current_branch() all_tags = set(git_common.tags()) all_branches = set(git_common.branches()) if current in all_branches: all_branches.remove(current) merge_base_map = {} for branch in all_branches: merge_base = git_common.get_or_create_merge_base(branch) if merge_base: merge_base_map.setdefault(merge_base, set()).add(branch) for merge_base, branches in merge_base_map.items(): merge_base_map[merge_base] = ', '.join(branches) try: for line in log_proc.stdout: if b'\x00' not in line: outbuf.write(line) continue graph, commit, branch_list, commit_date, subject = _parse_log_line( line) if 'HEAD' in branch_list: graph = graph.replace('*', BLUE_BACK + '*') line = '{graph}{commit}\t{branches}{date} ~ {subject}'.format( graph=graph, commit=BRIGHT_RED + commit[:10] + RESET, branches=_color_branch_list(branch_list, all_branches, all_tags, current), date=YELLOW + commit_date + RESET, subject=subject) if commit in merge_base_map: line += ' <({})'.format(WHITE + merge_base_map[commit] + RESET) line += os.linesep outbuf.write(line.encode('utf-8', 'replace')) except (BrokenPipeError, KeyboardInterrupt): pass return 0
def main(args): parser = argparse.ArgumentParser( formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument('branch_name') g = parser.add_mutually_exclusive_group() g.add_argument('--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('--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.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
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(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(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) 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=None): parser = argparse.ArgumentParser() parser.add_argument('--verbose', '-v', action='store_true') parser.add_argument('--keep-going', '-k', action='store_true', help='Keep processing past failed rebases.') parser.add_argument('--no_fetch', '--no-fetch', '-n', action='store_true', help='Skip fetching remotes.') opts = parser.parse_args(args) if opts.verbose: # pragma: no cover logging.getLogger().setLevel(logging.DEBUG) # TODO(iannucci): snapshot all branches somehow, so we can implement # `git rebase-update --undo`. # * Perhaps just copy packed-refs + refs/ + logs/ to the side? # * commit them to a secret ref? # * Then we could view a summary of each run as a # `diff --stat` on that secret ref. if git.in_rebase(): # TODO(iannucci): Be able to resume rebase with flags like --continue, # etc. print ( 'Rebase in progress. Please complete the rebase before running ' '`git rebase-update`.' ) return 1 return_branch, return_workdir = find_return_branch_workdir() os.chdir(git.run('rev-parse', '--show-toplevel')) if git.current_branch() == 'HEAD': if git.run('status', '--porcelain'): print 'Cannot rebase-update with detached head + uncommitted changes.' return 1 else: git.freeze() # just in case there are any local changes. skipped, branch_tree = git.get_branch_tree() for branch in skipped: print 'Skipping %s: No upstream specified' % branch if not opts.no_fetch: fetch_remotes(branch_tree) merge_base = {} for branch, parent in branch_tree.iteritems(): merge_base[branch] = git.get_or_create_merge_base(branch, parent) logging.debug('branch_tree: %s' % pformat(branch_tree)) logging.debug('merge_base: %s' % pformat(merge_base)) retcode = 0 unrebased_branches = [] # Rebase each branch starting with the root-most branches and working # towards the leaves. for branch, parent in git.topo_iter(branch_tree): if git.is_dormant(branch): print 'Skipping dormant branch', branch else: ret = rebase_branch(branch, parent, merge_base[branch]) if not ret: retcode = 1 if opts.keep_going: print '--keep-going set, continuing with next branch.' unrebased_branches.append(branch) if git.in_rebase(): git.run_with_retcode('rebase', '--abort') if git.in_rebase(): # pragma: no cover print 'Failed to abort rebase. Something is really wrong.' break else: break if unrebased_branches: print print 'The following branches could not be cleanly rebased:' for branch in unrebased_branches: print ' %s' % branch if not retcode: remove_empty_branches(branch_tree) # return_branch may not be there any more. if return_branch in git.branches(): git.run('checkout', return_branch) git.thaw() else: root_branch = git.root() if return_branch != 'HEAD': print ( "%r was merged with its parent, checking out %r instead." % (return_branch, root_branch) ) git.run('checkout', root_branch) if return_workdir: os.chdir(return_workdir) git.set_config(STARTING_BRANCH_KEY, '') git.set_config(STARTING_WORKDIR_KEY, '') return retcode
def rebase_branch(branch, parent, start_hash): logging.debug('considering %s(%s) -> %s(%s) : %s', branch, git.hash_one(branch), parent, git.hash_one(parent), start_hash) # If parent has FROZEN commits, don't base branch on top of them. Instead, # base branch on top of whatever commit is before them. back_ups = 0 orig_parent = parent while git.run('log', '-n1', '--format=%s', parent, '--').startswith(git.FREEZE): back_ups += 1 parent = git.run('rev-parse', parent+'~') if back_ups: logging.debug('Backed parent up by %d from %s to %s', back_ups, orig_parent, parent) if git.hash_one(parent) != start_hash: # Try a plain rebase first print 'Rebasing:', branch rebase_ret = git.rebase(parent, start_hash, branch, abort=True) if not rebase_ret.success: # TODO(iannucci): Find collapsible branches in a smarter way? print "Failed! Attempting to squash", branch, "...", squash_branch = branch+"_squash_attempt" git.run('checkout', '-b', squash_branch) git.squash_current_branch(merge_base=start_hash) # Try to rebase the branch_squash_attempt branch to see if it's empty. squash_ret = git.rebase(parent, start_hash, squash_branch, abort=True) empty_rebase = git.hash_one(squash_branch) == git.hash_one(parent) git.run('checkout', branch) git.run('branch', '-D', squash_branch) if squash_ret.success and empty_rebase: print 'Success!' git.squash_current_branch(merge_base=start_hash) git.rebase(parent, start_hash, branch) else: print "Failed!" print # rebase and leave in mid-rebase state. # This second rebase attempt should always fail in the same # way that the first one does. If it magically succeeds then # something very strange has happened. second_rebase_ret = git.rebase(parent, start_hash, branch) if second_rebase_ret.success: # pragma: no cover print "Second rebase succeeded unexpectedly!" print "Please see: http://crbug.com/425696" print "First rebased failed with:" print rebase_ret.stderr else: print "Here's what git-rebase (squashed) had to say:" print print squash_ret.stdout print squash_ret.stderr print textwrap.dedent( """\ Squashing failed. You probably have a real merge conflict. Your working copy is in mid-rebase. Either: * completely resolve like a normal git-rebase; OR * abort the rebase and mark this branch as dormant: git config branch.%s.dormant true And then run `git rebase-update` again to resume. """ % branch) return False else: print '%s up-to-date' % branch git.remove_merge_base(branch) git.get_or_create_merge_base(branch) return True
def main(args=None): parser = argparse.ArgumentParser() parser.add_argument('--verbose', '-v', action='store_true') parser.add_argument('--no_fetch', '--no-fetch', '-n', action='store_true', help='Skip fetching remotes.') opts = parser.parse_args(args) if opts.verbose: # pragma: no cover logging.getLogger().setLevel(logging.DEBUG) # TODO(iannucci): snapshot all branches somehow, so we can implement # `git rebase-update --undo`. # * Perhaps just copy packed-refs + refs/ + logs/ to the side? # * commit them to a secret ref? # * Then we could view a summary of each run as a # `diff --stat` on that secret ref. if git.in_rebase(): # TODO(iannucci): Be able to resume rebase with flags like --continue, # etc. print( 'Rebase in progress. Please complete the rebase before running ' '`git rebase-update`.') return 1 return_branch, return_workdir = find_return_branch_workdir() os.chdir(git.run('rev-parse', '--show-toplevel')) if git.current_branch() == 'HEAD': if git.run('status', '--porcelain'): print 'Cannot rebase-update with detached head + uncommitted changes.' return 1 else: git.freeze() # just in case there are any local changes. skipped, branch_tree = git.get_branch_tree() for branch in skipped: print 'Skipping %s: No upstream specified' % branch if not opts.no_fetch: fetch_remotes(branch_tree) merge_base = {} for branch, parent in branch_tree.iteritems(): merge_base[branch] = git.get_or_create_merge_base(branch, parent) logging.debug('branch_tree: %s' % pformat(branch_tree)) logging.debug('merge_base: %s' % pformat(merge_base)) retcode = 0 # Rebase each branch starting with the root-most branches and working # towards the leaves. for branch, parent in git.topo_iter(branch_tree): if git.is_dormant(branch): print 'Skipping dormant branch', branch else: ret = rebase_branch(branch, parent, merge_base[branch]) if not ret: retcode = 1 break if not retcode: remove_empty_branches(branch_tree) # return_branch may not be there any more. if return_branch in git.branches(): git.run('checkout', return_branch) git.thaw() else: root_branch = git.root() if return_branch != 'HEAD': print( "%r was merged with its parent, checking out %r instead." % (return_branch, root_branch)) git.run('checkout', root_branch) if return_workdir: os.chdir(return_workdir) git.set_config(STARTING_BRANCH_KEY, '') git.set_config(STARTING_WORKDIR_KEY, '') return retcode
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)
def rebase_branch(branch, parent, start_hash): logging.debug('considering %s(%s) -> %s(%s) : %s', branch, git.hash_one(branch), parent, git.hash_one(parent), start_hash) # If parent has FROZEN commits, don't base branch on top of them. Instead, # base branch on top of whatever commit is before them. back_ups = 0 orig_parent = parent while git.run('log', '-n1', '--format=%s', parent, '--').startswith(git.FREEZE): back_ups += 1 parent = git.run('rev-parse', parent + '~') if back_ups: logging.debug('Backed parent up by %d from %s to %s', back_ups, orig_parent, parent) if git.hash_one(parent) != start_hash: # Try a plain rebase first print 'Rebasing:', branch rebase_ret = git.rebase(parent, start_hash, branch, abort=True) if not rebase_ret.success: # TODO(iannucci): Find collapsible branches in a smarter way? print "Failed! Attempting to squash", branch, "...", squash_branch = branch + "_squash_attempt" git.run('checkout', '-b', squash_branch) git.squash_current_branch(merge_base=start_hash) # Try to rebase the branch_squash_attempt branch to see if it's empty. squash_ret = git.rebase(parent, start_hash, squash_branch, abort=True) empty_rebase = git.hash_one(squash_branch) == git.hash_one(parent) git.run('checkout', branch) git.run('branch', '-D', squash_branch) if squash_ret.success and empty_rebase: print 'Success!' git.squash_current_branch(merge_base=start_hash) git.rebase(parent, start_hash, branch) else: print "Failed!" print # rebase and leave in mid-rebase state. # This second rebase attempt should always fail in the same # way that the first one does. If it magically succeeds then # something very strange has happened. second_rebase_ret = git.rebase(parent, start_hash, branch) if second_rebase_ret.success: # pragma: no cover print "Second rebase succeeded unexpectedly!" print "Please see: http://crbug.com/425696" print "First rebased failed with:" print rebase_ret.stderr else: print "Here's what git-rebase (squashed) had to say:" print print squash_ret.stdout print squash_ret.stderr print textwrap.dedent("""\ Squashing failed. You probably have a real merge conflict. Your working copy is in mid-rebase. Either: * completely resolve like a normal git-rebase; OR * abort the rebase and mark this branch as dormant: git config branch.%s.dormant true And then run `git rebase-update` again to resume. """ % branch) return False else: print '%s up-to-date' % branch git.remove_merge_base(branch) git.get_or_create_merge_base(branch) return True
def main(args=None): parser = argparse.ArgumentParser() parser.add_argument('--verbose', '-v', action='store_true') parser.add_argument('--keep-going', '-k', action='store_true', help='Keep processing past failed rebases.') parser.add_argument('--no_fetch', '--no-fetch', '-n', action='store_true', help='Skip fetching remotes.') parser.add_argument( '--current', action='store_true', help='Only rebase the current branch.') parser.add_argument('branches', nargs='*', help='Branches to be rebased. All branches are assumed ' 'if none specified.') opts = parser.parse_args(args) if opts.verbose: # pragma: no cover logging.getLogger().setLevel(logging.DEBUG) # TODO(iannucci): snapshot all branches somehow, so we can implement # `git rebase-update --undo`. # * Perhaps just copy packed-refs + refs/ + logs/ to the side? # * commit them to a secret ref? # * Then we could view a summary of each run as a # `diff --stat` on that secret ref. if git.in_rebase(): # TODO(iannucci): Be able to resume rebase with flags like --continue, # etc. print('Rebase in progress. Please complete the rebase before running ' '`git rebase-update`.') return 1 return_branch, return_workdir = find_return_branch_workdir() os.chdir(git.run('rev-parse', '--show-toplevel')) if git.current_branch() == 'HEAD': if git.run('status', '--porcelain'): print('Cannot rebase-update with detached head + uncommitted changes.') return 1 else: git.freeze() # just in case there are any local changes. branches_to_rebase = set(opts.branches) if opts.current: branches_to_rebase.add(git.current_branch()) skipped, branch_tree = git.get_branch_tree() if branches_to_rebase: skipped = set(skipped).intersection(branches_to_rebase) for branch in skipped: print('Skipping %s: No upstream specified' % branch) if not opts.no_fetch: fetch_remotes(branch_tree) merge_base = {} for branch, parent in branch_tree.items(): merge_base[branch] = git.get_or_create_merge_base(branch, parent) logging.debug('branch_tree: %s' % pformat(branch_tree)) logging.debug('merge_base: %s' % pformat(merge_base)) retcode = 0 unrebased_branches = [] # Rebase each branch starting with the root-most branches and working # towards the leaves. for branch, parent in git.topo_iter(branch_tree): # Only rebase specified branches, unless none specified. if branches_to_rebase and branch not in branches_to_rebase: continue if git.is_dormant(branch): print('Skipping dormant branch', branch) else: ret = rebase_branch(branch, parent, merge_base[branch]) if not ret: retcode = 1 if opts.keep_going: print('--keep-going set, continuing with next branch.') unrebased_branches.append(branch) if git.in_rebase(): git.run_with_retcode('rebase', '--abort') if git.in_rebase(): # pragma: no cover print('Failed to abort rebase. Something is really wrong.') break else: break if unrebased_branches: print() print('The following branches could not be cleanly rebased:') for branch in unrebased_branches: print(' %s' % branch) if not retcode: remove_empty_branches(branch_tree) # return_branch may not be there any more. if return_branch in git.branches(): git.run('checkout', return_branch) git.thaw() else: root_branch = git.root() if return_branch != 'HEAD': print("%s was merged with its parent, checking out %s instead." % (git.unicode_repr(return_branch), git.unicode_repr(root_branch))) git.run('checkout', root_branch) # return_workdir may also not be there any more. if return_workdir: try: os.chdir(return_workdir) except OSError as e: print( "Unable to return to original workdir %r: %s" % (return_workdir, e)) git.set_config(STARTING_BRANCH_KEY, '') git.set_config(STARTING_WORKDIR_KEY, '') return retcode
def main(args): """Runs cpplint on the current changelist.""" """Adapted from git_cl.py CMDlint """ parser = git_cl.OptionParser() parser.add_option('--filter', action='append', metavar='-x,+y', help='Comma-separated list of cpplint\'s category-filters') parser.add_option('--project_root') parser.add_option('--base_branch') options, args = parser.parse_args(args) # Access to a protected member _XX of a client class # pylint: disable=protected-access try: import cpplint import cpplint_chromium except ImportError: print('Your depot_tools is missing cpplint.py and/or cpplint_chromium.py.') return 1 # Change the current working directory before calling lint so that it # shows the correct base. settings = git_cl.settings previous_cwd = os.getcwd() os.chdir(settings.GetRoot()) cl = git_cl.Changelist() base_branch = options.base_branch try: print('Running cpplint...') files = cl.GetAffectedFiles(git_common.get_or_create_merge_base(cl.GetBranch(), base_branch)) if not files: print('Cannot lint an empty CL') return 0 # Process cpplints arguments if any. command = args + files if options.filter: command = ['--filter=' + ','.join(options.filter)] + command if options.project_root: command = ['--project_root=' + options.project_root.replace('\\', '/')] + command filenames = cpplint.ParseArguments(command) white_regex = re.compile(settings.GetLintRegex()) black_regex = re.compile(settings.GetLintIgnoreRegex()) extra_check_functions = [cpplint_chromium.CheckPointerDeclarationWhitespace] for filename in filenames: if white_regex.match(filename): if black_regex.match(filename): print('Ignoring file %s' % filename) else: cpplint.ProcessFile(filename, cpplint._cpplint_state.verbose_level, extra_check_functions) else: print('Skipping file %s' % filename) # Run format checks upstream_branch = cl.GetUpstreamBranch() format_output = None if base_branch and not (base_branch in upstream_branch): print('Skipping clang/gn format check because base_branch is %s instead of %s' % (base_branch, upstream_branch)) else: format_output = RunFormatCheck(upstream_branch) finally: os.chdir(previous_cwd) if format_output: print(format_output) return 1 if cpplint._cpplint_state.error_count != 0: print('cpplint errors found: %d\n' % cpplint._cpplint_state.error_count) return 1 print('lint and format checks succeeded') return 0
def main(argv): if '-h' in argv: print_help() return 0 map_extra = get_config_list('depot_tools.map_extra') fmt = '%C(red bold)%h%x09%Creset%C(green)%d%Creset %C(yellow)%cd%Creset ~ %s' log_proc = subprocess2.Popen( [GIT_EXE, 'log', '--graph', '--branches', '--tags', root(), '--color=always', '--date=short', ('--pretty=format:' + fmt) ] + map_extra + argv, stdout=subprocess2.PIPE, shell=False) current = current_branch() all_branches = set(branches()) merge_base_map = {b: get_or_create_merge_base(b) for b in all_branches} merge_base_map = {b: v for b, v in merge_base_map.iteritems() if v} if current in all_branches: all_branches.remove(current) all_tags = set(tags()) try: for line in log_proc.stdout.xreadlines(): if merge_base_map: commit = line[line.find(BRIGHT_RED)+len(BRIGHT_RED):line.find('\t')] base_for_branches = set() for branch, sha in merge_base_map.iteritems(): if sha.startswith(commit): base_for_branches.add(branch) if base_for_branches: newline = '\r\n' if line.endswith('\r\n') else '\n' line = line.rstrip(newline) line += ''.join( (BRIGHT, WHITE, ' <(%s)' % (', '.join(base_for_branches)), RESET, newline)) for b in base_for_branches: del merge_base_map[b] start = line.find(GREEN+' (') end = line.find(')', start) if start != -1 and end != -1: start += len(GREEN) + 2 branch_list = line[start:end].split(', ') branches_str = '' if branch_list: colored_branches = [] head_marker = '' for b in branch_list: if b == "HEAD": head_marker = BLUEBAK+BRIGHT+'*' continue if b == current: colored_branches.append(CYAN+BRIGHT+b+RESET) current = None elif b in all_branches: colored_branches.append(GREEN+BRIGHT+b+RESET) all_branches.remove(b) elif b in all_tags: colored_branches.append(MAGENTA+BRIGHT+b+RESET) elif b.startswith('tag: '): colored_branches.append(MAGENTA+BRIGHT+b[5:]+RESET) else: colored_branches.append(RED+b) branches_str = '(%s) ' % ((GREEN+", ").join(colored_branches)+GREEN) line = "%s%s%s" % (line[:start-1], branches_str, line[end+5:]) if head_marker: line = line.replace('*', head_marker, 1) sys.stdout.write(line) except (IOError, KeyboardInterrupt): pass finally: sys.stderr.close() sys.stdout.close() return 0
def main(argv): if '-h' in argv: print_help() return 0 map_extra = get_config_list('depot_tools.map_extra') fmt = '%C(red bold)%h%x09%Creset%C(green)%d%Creset %C(yellow)%cd%Creset ~ %s' log_proc = subprocess2.Popen([ GIT_EXE, 'log', '--graph', '--branches', '--tags', root(), '--color=always', '--date=short', ('--pretty=format:' + fmt) ] + map_extra + argv, stdout=subprocess2.PIPE, shell=False) current = current_branch() all_branches = set(branches()) merge_base_map = {b: get_or_create_merge_base(b) for b in all_branches} merge_base_map = {b: v for b, v in merge_base_map.items() if v} if current in all_branches: all_branches.remove(current) all_tags = set(tags()) try: for line in log_proc.stdout.xreadlines(): if merge_base_map: commit = line[line.find(BRIGHT_RED) + len(BRIGHT_RED):line.find('\t')] base_for_branches = set() for branch, sha in merge_base_map.items(): if sha.startswith(commit): base_for_branches.add(branch) if base_for_branches: newline = '\r\n' if line.endswith('\r\n') else '\n' line = line.rstrip(newline) line += ''.join( (BRIGHT, WHITE, ' <(%s)' % (', '.join(base_for_branches)), RESET, newline)) for b in base_for_branches: del merge_base_map[b] start = line.find(GREEN + ' (') end = line.find(')', start) if start != -1 and end != -1: start += len(GREEN) + 2 branch_list = line[start:end].split(', ') branches_str = '' if branch_list: colored_branches = [] head_marker = '' for b in branch_list: if b == "HEAD": head_marker = BLUEBAK + BRIGHT + '*' continue if b == current: colored_branches.append(CYAN + BRIGHT + b + RESET) current = None elif b in all_branches: colored_branches.append(GREEN + BRIGHT + b + RESET) all_branches.remove(b) elif b in all_tags: colored_branches.append(MAGENTA + BRIGHT + b + RESET) elif b.startswith('tag: '): colored_branches.append(MAGENTA + BRIGHT + b[5:] + RESET) else: colored_branches.append(RED + b) branches_str = '(%s) ' % ( (GREEN + ", ").join(colored_branches) + GREEN) line = "%s%s%s" % (line[:start - 1], branches_str, line[end + 5:]) if head_marker: line = line.replace('*', head_marker, 1) sys.stdout.write(line) except (IOError, KeyboardInterrupt): pass finally: sys.stderr.close() sys.stdout.close() return 0
def main(args): """Runs cpplint on the current changelist.""" """Adapted from git_cl.py CMDlint """ parser = git_cl.OptionParser() parser.add_option( '--filter', action='append', metavar='-x,+y', help='Comma-separated list of cpplint\'s category-filters') parser.add_option('--project_root') parser.add_option('--base_branch') options, args = parser.parse_args(args) # Access to a protected member _XX of a client class # pylint: disable=protected-access try: import cpplint import cpplint_chromium except ImportError: print( 'Your depot_tools is missing cpplint.py and/or cpplint_chromium.py.' ) return 1 # Change the current working directory before calling lint so that it # shows the correct base. settings = git_cl.settings previous_cwd = os.getcwd() os.chdir(settings.GetRoot()) exit_code = 0 # Check for clang/gn format errors. cl = git_cl.Changelist() upstream_branch = cl.GetUpstreamBranch() upstream_commit = git_cl.RunGit(['merge-base', 'HEAD', upstream_branch]) try: if HasFormatErrors(upstream_commit): print('Format check failed. Run npm format to fix.') exit_code = 1 except: e = sys.exc_info()[1] print('Error running format check: %s' % e.info) exit_code = 1 if exit_code == 0: print('Format check succeeded.') print('Running cpplint...') try: files = cl.GetAffectedFiles( git_common.get_or_create_merge_base(cl.GetBranch(), options.base_branch)) if not files: print('Cannot lint an empty CL') return 0 # Process cpplints arguments if any. command = args + files if options.filter: command = ['--filter=' + ','.join(options.filter)] + command if options.project_root: command = ['--project_root=' + options.project_root] + command filenames = cpplint.ParseArguments(command) white_regex = re.compile(settings.GetLintRegex()) black_regex = re.compile(settings.GetLintIgnoreRegex()) extra_check_functions = [ cpplint_chromium.CheckPointerDeclarationWhitespace ] for filename in filenames: if white_regex.match(filename): if black_regex.match(filename): print('Ignoring file %s' % filename) else: cpplint.ProcessFile(filename, cpplint._cpplint_state.verbose_level, extra_check_functions) else: print('Skipping file %s' % filename) finally: os.chdir(previous_cwd) print('cpplint errors found: %d\n' % cpplint._cpplint_state.error_count) if cpplint._cpplint_state.error_count != 0: return 1 return exit_code
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 >> sys.stderr, msg % branch 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 >> 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'])