def init_remotes(self, remotes, per_remote_overrides=(),
                     per_remote_only=PER_REMOTE_ONLY,
                     global_only=GLOBAL_ONLY):
        '''
        Initialize remotes
        '''
        # The global versions of the auth params (gitfs_user,
        # gitfs_password, etc.) default to empty strings. If any of them
        # are defined and the provider is not one that supports auth, then
        # error out and do not proceed.
        override_params = copy.deepcopy(per_remote_overrides)
        global_auth_params = [
            '{0}_{1}'.format(self.role, x) for x in AUTH_PARAMS
            if self.opts['{0}_{1}'.format(self.role, x)]
        ]
        if self.provider in AUTH_PROVIDERS:
            override_params += AUTH_PARAMS
        elif global_auth_params:
            msg = (
                '{0} authentication was configured, but the \'{1}\' '
                '{0}_provider does not support authentication. The '
                'providers for which authentication is supported in {0} '
                'are: {2}.'.format(
                    self.role, self.provider, ', '.join(AUTH_PROVIDERS)
                )
            )
            if self.role == 'gitfs':
                msg += (
                    ' See the GitFS Walkthrough in the Salt documentation '
                    'for further information.'
                )
            log.critical(msg)
            failhard(self.role)

        per_remote_defaults = {}
        global_values = set(override_params)
        global_values.update(set(global_only))
        for param in global_values:
            key = '{0}_{1}'.format(self.role, param)
            if key not in self.opts:
                log.critical(
                    'Key \'%s\' not present in global configuration. This is '
                    'a bug, please report it.', key
                )
                failhard(self.role)
            per_remote_defaults[param] = enforce_types(key, self.opts[key])

        self.remotes = []
        for remote in remotes:
            repo_obj = self.git_providers[self.provider](
                self.opts,
                remote,
                per_remote_defaults,
                per_remote_only,
                override_params,
                self.cache_root,
                self.role
            )
            if hasattr(repo_obj, 'repo'):
                # Sanity check and assign the credential parameter
                repo_obj.verify_auth()
                repo_obj.setup_callbacks()
                if self.opts['__role'] == 'minion' and repo_obj.new:
                    # Perform initial fetch on masterless minion
                    repo_obj.fetch()

                # Reverse map to be used when running envs() to detect the
                # available envs.
                repo_obj.saltenv_revmap = {}

                for saltenv, saltenv_conf in six.iteritems(repo_obj.saltenv):
                    if 'ref' in saltenv_conf:
                        ref = saltenv_conf['ref']
                        repo_obj.saltenv_revmap.setdefault(
                            ref, []).append(saltenv)

                        if saltenv == 'base':
                            # Remove redundant 'ref' config for base saltenv
                            repo_obj.saltenv[saltenv].pop('ref')
                            if ref != repo_obj.base:
                                log.warning(
                                    'The \'base\' environment has been '
                                    'defined in the \'saltenv\' param for %s '
                                    'remote %s and will override the '
                                    'branch/tag specified by %s_base (or a '
                                    'per-remote \'base\' parameter).',
                                    self.role, repo_obj.id, self.role
                                )
                                # Rewrite 'base' config param
                                repo_obj.base = ref

                # Build list of all envs defined by ref mappings in the
                # per-remote 'saltenv' param. We won't add any matching envs
                # from the global saltenv map to the revmap.
                all_envs = []
                for env_names in six.itervalues(repo_obj.saltenv_revmap):
                    all_envs.extend(env_names)

                # Add the global saltenv map to the reverse map, skipping envs
                # explicitly mapped in the per-remote 'saltenv' param.
                for key, conf in six.iteritems(repo_obj.global_saltenv):
                    if key not in all_envs and 'ref' in conf:
                        repo_obj.saltenv_revmap.setdefault(
                            conf['ref'], []).append(key)

                self.remotes.append(repo_obj)

        # Don't allow collisions in cachedir naming
        cachedir_map = {}
        for repo in self.remotes:
            cachedir_map.setdefault(repo.cachedir, []).append(repo.id)

        collisions = [x for x in cachedir_map if len(cachedir_map[x]) > 1]
        if collisions:
            for dirname in collisions:
                log.critical(
                    'The following %s remotes have conflicting cachedirs: '
                    '%s. Resolve this using a per-remote parameter called '
                    '\'name\'.', self.role, ', '.join(cachedir_map[dirname])
                )
                failhard(self.role)

        if any(x.new for x in self.remotes):
            self.write_remote_map()