docs: def get_repos(config, force=False):
      """Return a :py:obj:`list` list of repos from config file.
      :param config: the repos config in :py:class:`dict` format.
      :param bool force: Force aggregate dirty repos or not.
      :type config: dict
      :rtype: list
      """
      repo_list = []
      for directory, repo_data in config.items():
          if not os.path.isabs(directory):
              directory = os.path.abspath(directory)
          repo_dict = {
              'cwd': directory,
              'defaults': repo_data.get('defaults', dict()),
              'force': force,
          }
          remote_names = set()
          if 'remotes' in repo_data:
              repo_dict['remotes'] = []
              remotes_data = repo_data['remotes'] or {}
              for remote_name, url in remotes_data.items():
                  if not url:
                      raise ConfigException(
                          '%s: No url defined for remote %s.' %
                          (directory, remote_name))
                  remote_dict = {
                      'name': remote_name,
                      'url': url
                  }
                  repo_dict['remotes'].append(remote_dict)
                  remote_names.add(remote_name)
              if not remote_names:
                  raise ConfigException(
                      '%s: You should at least define one remote.' % directory)
          else:
              raise ConfigException('%s: remotes is not defined.' % directory)
          if 'merges' in repo_data:
              merges = []
              merge_data = repo_data.get('merges') or []
              for merge in merge_data:
                  try:
                      # Assume parts is a str
                      parts = merge.split(' ')
                      if len(parts) != 2:
                          raise ConfigException(
                              '%s: Merge must be formatted as '
                              '"remote_name ref".' % directory)
                      merge = {
                          "remote": parts[0],
                          "ref": parts[1],
                      }
                  except AttributeError:
                      # Parts is a dict
                      try:
                          merge["remote"] = str(merge["remote"])
                          merge["ref"] = str(merge["ref"])
                      except KeyError:
                          raise ConfigException(
                              '%s: Merge lacks mandatory '
                              '`remote` or `ref` keys.' % directory)
                  # Check remote is available
                  if merge["remote"] not in remote_names:
                      raise ConfigException(
                          '%s: Merge remote %s not defined in remotes.' %
                          (directory, merge["remote"]))
                  merges.append(merge)
              repo_dict['merges'] = merges
              if not merges:
                  raise ConfigException(
                      '%s: You should at least define one merge.' % directory)
          else:
              raise ConfigException(
                  '%s: merges is not defined.' % directory)
          # Only fetch required remotes by default
          repo_dict["fetch_all"] = repo_data.get("fetch_all", False)
          if isinstance(repo_dict["fetch_all"], string_types):
              repo_dict["fetch_all"] = frozenset((repo_dict["fetch_all"],))
          elif isinstance(repo_dict["fetch_all"], list):
              repo_dict["fetch_all"] = frozenset(repo_dict["fetch_all"])
          if 'target' not in repo_data:
              raise ConfigException('%s: No target defined.' % directory)
          parts = (repo_data.get('target') or "") .split(' ')
          if len(parts) != 2:
              raise ConfigException(
                  '%s: Target must be formatted as '
                  '"remote_name branch_name"' % directory)
  
          remote_name, branch = repo_data.get('target').split(' ')
          if remote_name not in remote_names:
              raise ConfigException(
                  '%s: Target remote %s not defined in remotes.' %
                  (directory, remote_name))
          repo_dict['target'] = {
              'remote': remote_name,
              'branch': branch,
          }
          commands = []
          if 'shell_command_after' in repo_data:
              cmds = repo_data['shell_command_after']
              # if str: turn to list
              if cmds:
                  if isinstance(cmds, string_types):
                      cmds = [cmds]
                  commands = cmds
          repo_dict['shell_command_after'] = commands
          repo_list.append(repo_dict)
      return repo_list