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
Exemple #3
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):
  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):
  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)
Exemple #6
0
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)
Exemple #7
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')
  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
Exemple #8
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
Exemple #9
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
Exemple #10
0
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
Exemple #11
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)
Exemple #12
0
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
Exemple #20
0
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
Exemple #21
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())
  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
Exemple #22
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
Exemple #23
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
Exemple #24
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'])