def start(self):
    self.__branches_info = get_branches_info(
        include_tracking_status=self.verbosity >= 1)
    roots = set()

    # A map of parents to a list of their children.
    for branch, branch_info in self.__branches_info.iteritems():
      if not branch_info:
        continue

      parent = branch_info.upstream
      if parent and not self.__branches_info[parent]:
        branch_upstream = upstream(branch)
        # If git can't find the upstream, mark the upstream as gone.
        if branch_upstream:
          parent = branch_upstream
        else:
          self.__gone_branches.add(parent)
        # A parent that isn't in the branches info is a root.
        roots.add(parent)

      self.__parent_map[parent].append(branch)

    self.__current_branch = current_branch()
    self.__current_hash = hash_one('HEAD', short=True)
    self.__tag_set = tags()

    if roots:
      for root in sorted(roots):
        self.__append_branch(root)
    else:
      no_branches = OutputLine()
      no_branches.append('No User Branches')
      self.output.append(no_branches)
Exemple #2
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)
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 #4
0
    def start(self):
        self.__branches_info = get_branches_info(
            include_tracking_status=self.verbosity >= 1)
        roots = set()

        # A map of parents to a list of their children.
        for branch, branch_info in self.__branches_info.iteritems():
            if not branch_info:
                continue

            parent = branch_info.upstream
            if not self.__branches_info[parent]:
                branch_upstream = upstream(branch)
                # If git can't find the upstream, mark the upstream as gone.
                if branch_upstream:
                    parent = branch_upstream
                else:
                    self.__gone_branches.add(parent)
                # A parent that isn't in the branches info is a root.
                roots.add(parent)

            self.__parent_map[parent].append(branch)

        self.__current_branch = current_branch()
        self.__current_hash = hash_one('HEAD', short=True)
        self.__tag_set = tags()

        if roots:
            for root in sorted(roots):
                self.__append_branch(root)
        else:
            no_branches = OutputLine()
            no_branches.append('No User Branches')
            self.output.append(no_branches)
def main(argv):
    colorama.init()
    assert len(argv) == 1, "No arguments expected"
    branch_map = {}
    par_map = collections.defaultdict(list)
    for branch in branches():
        par = upstream(branch) or NO_UPSTREAM
        branch_map[branch] = par
        par_map[par].append(branch)

    current = current_branch()
    hashes = hash_multi(current, *branch_map.keys())
    current_hash = hashes[0]
    par_hashes = {
        k: hashes[i + 1]
        for i, k in enumerate(branch_map.iterkeys())
    }
    par_hashes[NO_UPSTREAM] = 0
    tag_set = tags()
    while par_map:
        for parent in par_map:
            if parent not in branch_map:
                if parent not in par_hashes:
                    par_hashes[parent] = hash_one(parent)
                print_branch(current, current_hash, parent, par_hashes,
                             par_map, branch_map, tag_set)
                break
def main(args):
    parser = argparse.ArgumentParser(
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
        description=__doc__,
    )
    parser.add_argument('branch_name')
    g = parser.add_mutually_exclusive_group()
    g.add_argument('--upstream-current',
                   '--upstream_current',
                   action='store_true',
                   help='set upstream branch to current branch.')
    g.add_argument('--upstream',
                   metavar='REF',
                   default=root(),
                   help='upstream branch (or tag) to track.')
    g.add_argument('--inject-current',
                   '--inject_current',
                   action='store_true',
                   help='new branch adopts current branch\'s upstream,' +
                   ' and new branch becomes current branch\'s upstream.')
    g.add_argument('--lkgr',
                   action='store_const',
                   const='lkgr',
                   dest='upstream',
                   help='set basis ref for new branch to lkgr.')

    opts = parser.parse_args(args)

    try:
        if opts.inject_current:
            below = current_branch()
            if below is None:
                raise Exception('no current branch')
            above = upstream(below)
            if above is None:
                raise Exception('branch %s has no upstream' % (below))
            run('checkout', '--track', above, '-b', opts.branch_name)
            run('branch', '--set-upstream-to', opts.branch_name, below)
        elif opts.upstream_current:
            run('checkout', '--track', '-b', opts.branch_name)
        else:
            if opts.upstream in tags():
                # TODO(iannucci): ensure that basis_ref is an ancestor of HEAD?
                run('checkout', '--no-track', '-b', opts.branch_name,
                    hash_one(opts.upstream))
                set_config('branch.%s.remote' % opts.branch_name, '.')
                set_config('branch.%s.merge' % opts.branch_name, opts.upstream)
            else:
                # TODO(iannucci): Detect unclean workdir then stash+pop if we need to
                # teleport to a conflicting portion of history?
                run('checkout', '--track', opts.upstream, '-b',
                    opts.branch_name)
        get_or_create_merge_base(opts.branch_name)
    except subprocess2.CalledProcessError as cpe:
        sys.stdout.write(cpe.stdout)
        sys.stderr.write(cpe.stderr)
        return 1
    sys.stderr.write('Switched to branch %s.\n' % opts.branch_name)
    return 0
Exemple #7
0
def SplitCl(description_file, comment_file, changelist, cmd_upload):
    """"Splits a branch into smaller branches and uploads CLs.

  Args:
    description_file: File containing the description of uploaded CLs.
    comment_file: File containing the comment of uploaded CLs.
    changelist: The Changelist class.
    cmd_upload: The function associated with the git cl upload command.

  Returns:
    0 in case of success. 1 in case of error.
  """
    description = AddUploadedByGitClSplitToDescription(
        ReadFile(description_file))
    comment = ReadFile(comment_file) if comment_file else None

    try:
        EnsureInGitRepository()

        cl = changelist()
        change = cl.GetChange(cl.GetCommonAncestorWithUpstream(), None)
        files = change.AffectedFiles()

        if not files:
            print 'Cannot split an empty CL.'
            return 1

        author = git.run('config', 'user.email').strip() or None
        refactor_branch = git.current_branch()
        assert refactor_branch, "Can't run from detached branch."
        refactor_branch_upstream = git.upstream(refactor_branch)
        assert refactor_branch_upstream, \
            "Branch %s must have an upstream." % refactor_branch

        owners_database = owners.Database(change.RepositoryRoot(), file,
                                          os.path)
        owners_database.load_data_needed_for([f.LocalPath() for f in files])

        files_split_by_owners = GetFilesSplitByOwners(owners_database, files)

        print('Will split current branch (' + refactor_branch + ') in ' +
              str(len(files_split_by_owners)) + ' CLs.\n')

        for directory, files in files_split_by_owners.iteritems():
            # Use '/' as a path separator in the branch name and the CL description
            # and comment.
            directory = directory.replace(os.path.sep, '/')
            # Upload the CL.
            UploadCl(refactor_branch, refactor_branch_upstream, directory,
                     files, author, description, comment, owners_database,
                     changelist, cmd_upload)

        # Go back to the original branch.
        git.run('checkout', refactor_branch)

    except subprocess2.CalledProcessError as cpe:
        sys.stderr.write(cpe.stderr)
        return 1
    return 0
def main(args):
    root_ref = root()

    parser = argparse.ArgumentParser()
    g = parser.add_mutually_exclusive_group()
    g.add_argument('new_parent',
                   nargs='?',
                   help='New parent branch (or tag) to reparent to.')
    g.add_argument('--root',
                   action='store_true',
                   help='Reparent to the configured root branch (%s).' %
                   root_ref)
    g.add_argument('--lkgr',
                   action='store_true',
                   help='Reparent to the lkgr tag.')
    opts = parser.parse_args(args)

    # TODO(iannucci): Allow specification of the branch-to-reparent

    branch = current_branch()
    if opts.root:
        new_parent = root_ref
    elif opts.lkgr:
        new_parent = 'lkgr'
    else:
        new_parent = opts.new_parent
    cur_parent = upstream(branch)

    if branch == 'HEAD' or not branch:
        parser.error('Must be on the branch you want to reparent')
    if new_parent == cur_parent:
        parser.error('Cannot reparent a branch to its existing parent')

    mbase = get_or_create_merge_base(branch, cur_parent)

    all_tags = tags()
    if cur_parent in all_tags:
        cur_parent += ' [tag]'

    try:
        run('show-ref', new_parent)
    except subprocess2.CalledProcessError:
        print >> sys.stderr, 'fatal: invalid reference: %s' % new_parent
        return 1

    if new_parent in all_tags:
        print("Reparenting %s to track %s [tag] (was %s)" %
              (branch, new_parent, cur_parent))
        set_branch_config(branch, 'remote', '.')
        set_branch_config(branch, 'merge', new_parent)
    else:
        print("Reparenting %s to track %s (was %s)" %
              (branch, new_parent, cur_parent))
        run('branch', '--set-upstream-to', new_parent, branch)

    manual_merge_base(branch, mbase, new_parent)

    # TODO(iannucci): ONLY rebase-update the branch which moved (and dependants)
    return git_rebase_update.main(['--no-fetch'])
def main(args):
  root_ref = root()

  parser = argparse.ArgumentParser()
  g = parser.add_mutually_exclusive_group()
  g.add_argument('new_parent', nargs='?',
                 help='New parent branch (or tag) to reparent to.')
  g.add_argument('--root', action='store_true',
                 help='Reparent to the configured root branch (%s).' % root_ref)
  g.add_argument('--lkgr', action='store_true',
                 help='Reparent to the lkgr tag.')
  opts = parser.parse_args(args)

  # TODO(iannucci): Allow specification of the branch-to-reparent

  branch = current_branch()
  if opts.root:
    new_parent = root_ref
  elif opts.lkgr:
    new_parent = 'lkgr'
  else:
    if not opts.new_parent:
      parser.error('Must specify new parent somehow')
    new_parent = opts.new_parent
  cur_parent = upstream(branch)

  if branch == 'HEAD' or not branch:
    parser.error('Must be on the branch you want to reparent')
  if new_parent == cur_parent:
    parser.error('Cannot reparent a branch to its existing parent')

  mbase = get_or_create_merge_base(branch, cur_parent)

  all_tags = tags()
  if cur_parent in all_tags:
    cur_parent += ' [tag]'

  try:
    run('show-ref', new_parent)
  except subprocess2.CalledProcessError:
    print >> sys.stderr, 'fatal: invalid reference: %s' % new_parent
    return 1

  if new_parent in all_tags:
    print ("Reparenting %s to track %s [tag] (was %s)"
           % (branch, new_parent, cur_parent))
    set_branch_config(branch, 'remote', '.')
    set_branch_config(branch, 'merge', new_parent)
  else:
    print ("Reparenting %s to track %s (was %s)"
           % (branch, new_parent, cur_parent))
    run('branch', '--set-upstream-to', new_parent, branch)

  manual_merge_base(branch, mbase, new_parent)

  # TODO(iannucci): ONLY rebase-update the branch which moved (and dependants)
  return git_rebase_update.main(['--no-fetch'])
    def start(self):
        self.__branches_info = get_branches_info(
            include_tracking_status=self.verbosity >= 1)
        if (self.verbosity >= 2):
            # Avoid heavy import unless necessary.
            from git_cl import get_cl_statuses, color_for_status, Changelist

            change_cls = [
                Changelist(branchref='refs/heads/' + b)
                for b in self.__branches_info.keys() if b
            ]
            status_info = get_cl_statuses(change_cls,
                                          fine_grained=self.verbosity > 2,
                                          max_processes=self.maxjobs)

            # This is a blocking get which waits for the remote CL status to be
            # retrieved.
            for cl, status in status_info:
                self.__status_info[cl.GetBranch()] = (cl.GetIssueURL(),
                                                      color_for_status(status),
                                                      status)

        roots = set()

        # A map of parents to a list of their children.
        for branch, branch_info in self.__branches_info.items():
            if not branch_info:
                continue

            parent = branch_info.upstream
            if self.__check_cycle(branch):
                continue
            if not self.__branches_info[parent]:
                branch_upstream = upstream(branch)
                # If git can't find the upstream, mark the upstream as gone.
                if branch_upstream:
                    parent = branch_upstream
                else:
                    self.__gone_branches.add(parent)
                # A parent that isn't in the branches info is a root.
                roots.add(parent)

            self.__parent_map[parent].append(branch)

        self.__current_branch = current_branch()
        self.__current_hash = hash_one('HEAD', short=True)
        self.__tag_set = tags()

        if roots:
            for root in sorted(roots):
                self.__append_branch(root)
        else:
            no_branches = OutputLine()
            no_branches.append('No User Branches')
            self.output.append(no_branches)
def 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 start(self):
    self.__branches_info = get_branches_info(
        include_tracking_status=self.verbosity >= 1)
    if (self.verbosity >= 2):
      # Avoid heavy import unless necessary.
      from git_cl import get_cl_statuses, color_for_status, Changelist

      change_cls = [Changelist(branchref='refs/heads/'+b)
                    for b in self.__branches_info.keys() if b]
      status_info = get_cl_statuses(change_cls,
                                    fine_grained=self.verbosity > 2,
                                    max_processes=self.maxjobs)

      # This is a blocking get which waits for the remote CL status to be
      # retrieved.
      for cl, status in status_info:
        self.__status_info[cl.GetBranch()] = (cl.GetIssueURL(),
                                              color_for_status(status),
                                              status)

    roots = set()

    # A map of parents to a list of their children.
    for branch, branch_info in self.__branches_info.iteritems():
      if not branch_info:
        continue

      parent = branch_info.upstream
      if not self.__branches_info[parent]:
        branch_upstream = upstream(branch)
        # If git can't find the upstream, mark the upstream as gone.
        if branch_upstream:
          parent = branch_upstream
        else:
          self.__gone_branches.add(parent)
        # A parent that isn't in the branches info is a root.
        roots.add(parent)

      self.__parent_map[parent].append(branch)

    self.__current_branch = current_branch()
    self.__current_hash = hash_one('HEAD', short=True)
    self.__tag_set = tags()

    if roots:
      for root in sorted(roots):
        self.__append_branch(root)
    else:
      no_branches = OutputLine()
      no_branches.append('No User Branches')
      self.output.append(no_branches)
Exemple #13
0
    def start(self):
        self.__branches_info = get_branches_info(
            include_tracking_status=self.verbosity >= 1)
        if (self.verbosity >= 2):
            # Avoid heavy import unless necessary.
            from git_cl import get_cl_statuses

            status_info = get_cl_statuses(self.__branches_info.keys(),
                                          fine_grained=self.verbosity > 2,
                                          max_processes=self.maxjobs)

            for _ in xrange(len(self.__branches_info)):
                # This is a blocking get which waits for the remote CL status to be
                # retrieved.
                (branch, url, color) = status_info.next()
                self.__status_info[branch] = (url, color)

        roots = set()

        # A map of parents to a list of their children.
        for branch, branch_info in self.__branches_info.iteritems():
            if not branch_info:
                continue

            parent = branch_info.upstream
            if not self.__branches_info[parent]:
                branch_upstream = upstream(branch)
                # If git can't find the upstream, mark the upstream as gone.
                if branch_upstream:
                    parent = branch_upstream
                else:
                    self.__gone_branches.add(parent)
                # A parent that isn't in the branches info is a root.
                roots.add(parent)

            self.__parent_map[parent].append(branch)

        self.__current_branch = current_branch()
        self.__current_hash = hash_one('HEAD', short=True)
        self.__tag_set = tags()

        if roots:
            for root in sorted(roots):
                self.__append_branch(root)
        else:
            no_branches = OutputLine()
            no_branches.append('No User Branches')
            self.output.append(no_branches)
Exemple #14
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 #15
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(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)
Exemple #18
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
def main(argv):
  colorama.init()
  assert len(argv) == 1, "No arguments expected"
  branch_map = {}
  par_map = collections.defaultdict(list)
  for branch in branches():
    par = upstream(branch) or NO_UPSTREAM
    branch_map[branch] = par
    par_map[par].append(branch)

  current = current_branch()
  hashes = hash_multi(current, *branch_map.keys())
  current_hash = hashes[0]
  par_hashes = {k: hashes[i+1] for i, k in enumerate(branch_map.iterkeys())}
  par_hashes[NO_UPSTREAM] = 0
  tag_set = tags()
  while par_map:
    for parent in par_map:
      if parent not in branch_map:
        if parent not in par_hashes:
          par_hashes[parent] = hash_one(parent)
        print_branch(current, current_hash, parent, par_hashes, par_map,
                     branch_map, tag_set)
        break
 def _upfn(b):
     parent = upstream(b)
     if parent:
         return hash_one(parent)
 def _upfn(b):
   parent = upstream(b)
   if parent:
     return hash_one(parent)
Exemple #22
0
def SplitCl(description_file, comment_file, changelist, cmd_upload, dry_run,
            cq_dry_run, enable_auto_submit, repository_root):
    """"Splits a branch into smaller branches and uploads CLs.

  Args:
    description_file: File containing the description of uploaded CLs.
    comment_file: File containing the comment of uploaded CLs.
    changelist: The Changelist class.
    cmd_upload: The function associated with the git cl upload command.
    dry_run: Whether this is a dry run (no branches or CLs created).
    cq_dry_run: If CL uploads should also do a cq dry run.
    enable_auto_submit: If CL uploads should also enable auto submit.

  Returns:
    0 in case of success. 1 in case of error.
  """
    description = AddUploadedByGitClSplitToDescription(
        ReadFile(description_file))
    comment = ReadFile(comment_file) if comment_file else None

    try:
        EnsureInGitRepository()

        cl = changelist()
        upstream = cl.GetCommonAncestorWithUpstream()
        files = [
            (action.strip(), f)
            for action, f in scm.GIT.CaptureStatus(repository_root, upstream)
        ]

        if not files:
            print('Cannot split an empty CL.')
            return 1

        author = git.run('config', 'user.email').strip() or None
        refactor_branch = git.current_branch()
        assert refactor_branch, "Can't run from detached branch."
        refactor_branch_upstream = git.upstream(refactor_branch)
        assert refactor_branch_upstream, \
            "Branch %s must have an upstream." % refactor_branch

        owners_database = owners.Database(repository_root, open, os.path)
        owners_database.load_data_needed_for([f for _, f in files])

        files_split_by_owners = GetFilesSplitByOwners(owners_database, files)

        num_cls = len(files_split_by_owners)
        print('Will split current branch (' + refactor_branch + ') into ' +
              str(num_cls) + ' CLs.\n')
        if cq_dry_run and num_cls > CL_SPLIT_FORCE_LIMIT:
            print(
                'This will generate "%r" CLs. This many CLs can potentially generate'
                ' too much load on the build infrastructure. Please email'
                ' [email protected] to ensure that this won\'t  break anything.'
                ' The infra team reserves the right to cancel your jobs if they are'
                ' overloading the CQ.' % num_cls)
            answer = raw_input('Proceed? (y/n):')
            if answer.lower() != 'y':
                return 0

        for cl_index, (directory, files) in \
            enumerate(files_split_by_owners.items(), 1):
            # Use '/' as a path separator in the branch name and the CL description
            # and comment.
            directory = directory.replace(os.path.sep, '/')
            file_paths = [f for _, f in files]
            reviewers = owners_database.reviewers_for(file_paths, author)

            if dry_run:
                PrintClInfo(cl_index, num_cls, directory, file_paths,
                            description, reviewers)
            else:
                UploadCl(refactor_branch, refactor_branch_upstream, directory,
                         files, description, comment, reviewers, changelist,
                         cmd_upload, cq_dry_run, enable_auto_submit,
                         repository_root)

        # Go back to the original branch.
        git.run('checkout', refactor_branch)

    except subprocess2.CalledProcessError as cpe:
        sys.stderr.write(cpe.stderr)
        return 1
    return 0
Exemple #23
0
def SplitCl(description_file, comment_file, changelist, cmd_upload, dry_run,
            cq_dry_run):
  """"Splits a branch into smaller branches and uploads CLs.

  Args:
    description_file: File containing the description of uploaded CLs.
    comment_file: File containing the comment of uploaded CLs.
    changelist: The Changelist class.
    cmd_upload: The function associated with the git cl upload command.
    dry_run: Whether this is a dry run (no branches or CLs created).
    cq_dry_run: If CL uploads should also do a cq dry run.

  Returns:
    0 in case of success. 1 in case of error.
  """
  description = AddUploadedByGitClSplitToDescription(ReadFile(description_file))
  comment = ReadFile(comment_file) if comment_file else None

  try:
    EnsureInGitRepository()

    cl = changelist()
    change = cl.GetChange(cl.GetCommonAncestorWithUpstream(), None)
    files = change.AffectedFiles()

    if not files:
      print 'Cannot split an empty CL.'
      return 1

    author = git.run('config', 'user.email').strip() or None
    refactor_branch = git.current_branch()
    assert refactor_branch, "Can't run from detached branch."
    refactor_branch_upstream = git.upstream(refactor_branch)
    assert refactor_branch_upstream, \
        "Branch %s must have an upstream." % refactor_branch

    owners_database = owners.Database(change.RepositoryRoot(), file, os.path)
    owners_database.load_data_needed_for([f.LocalPath() for f in files])

    files_split_by_owners = GetFilesSplitByOwners(owners_database, files)

    num_cls = len(files_split_by_owners)
    print('Will split current branch (' + refactor_branch + ') into ' +
          str(num_cls) + ' CLs.\n')
    if cq_dry_run and num_cls > CL_SPLIT_FORCE_LIMIT:
      print (
        'This will generate "%r" CLs. This many CLs can potentially generate'
        ' too much load on the build infrastructure. Please email'
        ' [email protected] to ensure that this won\'t  break anything.'
        ' The infra team reserves the right to cancel your jobs if they are'
        ' overloading the CQ.') % num_cls
      answer = raw_input('Proceed? (y/n):')
      if answer.lower() != 'y':
        return 0

    for cl_index, (directory, files) in \
        enumerate(files_split_by_owners.iteritems(), 1):
      # Use '/' as a path separator in the branch name and the CL description
      # and comment.
      directory = directory.replace(os.path.sep, '/')
      file_paths = [f.LocalPath() for f in files]
      reviewers = owners_database.reviewers_for(file_paths, author)

      if dry_run:
        PrintClInfo(cl_index, num_cls, directory, file_paths, description,
                    reviewers)
      else:
        UploadCl(refactor_branch, refactor_branch_upstream, directory, files,
                 description, comment, reviewers, changelist, cmd_upload,
                 cq_dry_run)

    # Go back to the original branch.
    git.run('checkout', refactor_branch)

  except subprocess2.CalledProcessError as cpe:
    sys.stderr.write(cpe.stderr)
    return 1
  return 0
def main(args):
  root_ref = root()

  parser = argparse.ArgumentParser()
  g = parser.add_mutually_exclusive_group()
  g.add_argument('new_parent', nargs='?',
                 help='New parent branch (or tag) to reparent to.')
  g.add_argument('--root', action='store_true',
                 help='Reparent to the configured root branch (%s).' % root_ref)
  g.add_argument('--lkgr', action='store_true',
                 help='Reparent to the lkgr tag.')
  opts = parser.parse_args(args)

  # TODO(iannucci): Allow specification of the branch-to-reparent

  branch = current_branch()

  if opts.root:
    new_parent = root_ref
  elif opts.lkgr:
    new_parent = 'lkgr'
  else:
    if not opts.new_parent:
      parser.error('Must specify new parent somehow')
    new_parent = opts.new_parent
  cur_parent = upstream(branch)

  if branch == 'HEAD' or not branch:
    parser.error('Must be on the branch you want to reparent')
  if new_parent == cur_parent:
    parser.error('Cannot reparent a branch to its existing parent')

  if not cur_parent:
    msg = (
      "Unable to determine %s@{upstream}.\n\nThis can happen if you didn't use "
      "`git new-branch` to create the branch and haven't used "
      "`git branch --set-upstream-to` to assign it one.\n\nPlease assign an "
      "upstream branch and then run this command again."
    )
    print(msg % branch, file=sys.stderr)
    return 1

  mbase = get_or_create_merge_base(branch, cur_parent)

  all_tags = tags()
  if cur_parent in all_tags:
    cur_parent += ' [tag]'

  try:
    run('show-ref', new_parent)
  except subprocess2.CalledProcessError:
    print('fatal: invalid reference: %s' % new_parent, file=sys.stderr)
    return 1

  if new_parent in all_tags:
    print("Reparenting %s to track %s [tag] (was %s)" % (branch, new_parent,
                                                         cur_parent))
    set_branch_config(branch, 'remote', '.')
    set_branch_config(branch, 'merge', new_parent)
  else:
    print("Reparenting %s to track %s (was %s)" % (branch, new_parent,
                                                   cur_parent))
    run('branch', '--set-upstream-to', new_parent, branch)

  manual_merge_base(branch, mbase, new_parent)

  # ONLY rebase-update the branch which moved (and dependants)
  _, branch_tree = get_branch_tree()
  branches = [branch]
  for branch, parent in topo_iter(branch_tree):
    if parent in branches:
      branches.append(branch)
  return git_rebase_update.main(['--no-fetch'] + branches)