@unbare_repo
    def remove(self, module=True, force=False, configuration=True, dry_run=False):
        """Remove this submodule from the repository. This will remove our entry
        from the .gitmodules file and the entry in the .git/config file.

        :param module: If True, the module checkout we point to will be deleted
            as well. If the module is currently on a commit which is not part
            of any branch in the remote, if the currently checked out branch
            working tree, or untracked files,
            is ahead of its tracking branch,  if you have modifications in the
            In case the removal of the repository fails for these reasons, the
            submodule status will not have been altered.
            If this submodule has child-modules on its own, these will be deleted
            prior to touching the own module.
        :param force: Enforces the deletion of the module even though it contains
            modifications. This basically enforces a brute-force file system based
            deletion.
        :param configuration: if True, the submodule is deleted from the configuration,
            otherwise it isn't. Although this should be enabled most of the times,
            this flag enables you to safely delete the repository of your submodule.
        :param dry_run: if True, we will not actually do anything, but throw the errors
            we would usually throw
        :return: self
        :note: doesn't work in bare repositories
        :note: doesn't work atomically, as failure to remove any part of the submodule will leave
            an inconsistent state
        :raise InvalidGitRepositoryError: thrown if the repository cannot be deleted
        :raise OSError: if directories or files could not be removed"""
        if not (module or configuration):
            raise ValueError("Need to specify to delete at least the module, or the configuration")
        # END handle parameters

        # Recursively remove children of this submodule
        nc = 0
        for csm in self.children():
            nc += 1
            csm.remove(module, force, configuration, dry_run)
            del(csm)
        # end
        if configuration and not dry_run and nc > 0:
            # Assure we don't leave the parent repository in a dirty state, and commit our changes
            # It's important for recursive, unforced, deletions to work as expected
            self.module().index.commit("Removed at least one of child-modules of '%s'" % self.name)
        # end handle recursion

        # DELETE REPOSITORY WORKING TREE
        ################################
        if module and self.module_exists():
            mod = self.module()
            git_dir = mod.git_dir
            if force:
                # take the fast lane and just delete everything in our module path
                # TODO: If we run into permission problems, we have a highly inconsistent
                # state. Delete the .git folders last, start with the submodules first
                mp = self.abspath
                method = None
                if os.path.islink(mp):
                    method = os.remove
                elif os.path.isdir(mp):
                    method = rmtree
                elif os.path.exists(mp):
                    raise AssertionError("Cannot forcibly delete repository as it was neither a link, nor a directory")
                # END handle brutal deletion
                if not dry_run:
                    assert method
                    method(mp)
                # END apply deletion method
            else:
                # verify we may delete our module
                if mod.is_dirty(index=True, working_tree=True, untracked_files=True):
                    raise InvalidGitRepositoryError(
                        "Cannot delete module at %s with any modifications, unless force is specified"
                        % mod.working_tree_dir)
                # END check for dirt

                # figure out whether we have new commits compared to the remotes
                # NOTE: If the user pulled all the time, the remote heads might
                # not have been updated, so commits coming from the remote look
                # as if they come from us. But we stay strictly read-only and
                # don't fetch beforehand.
                for remote in mod.remotes:
                    num_branches_with_new_commits = 0
                    rrefs = remote.refs
                    for rref in rrefs:
                        num_branches_with_new_commits += len(mod.git.cherry(rref)) != 0
                    # END for each remote ref
                    # not a single remote branch contained all our commits
                    if num_branches_with_new_commits == len(rrefs):
                        raise InvalidGitRepositoryError(
                            "Cannot delete module at %s as there are new commits" % mod.working_tree_dir)
                    # END handle new commits
                    # have to manually delete references as python's scoping is
                    # not existing, they could keep handles open ( on windows this is a problem )
                    if len(rrefs):
                        del(rref)
                    # END handle remotes
                    del(rrefs)
                    del(remote)
                # END for each remote

                # finally delete our own submodule
                if not dry_run:
                    wtd = mod.working_tree_dir
                    del(mod)        # release file-handles (windows)
                    rmtree(wtd)
                # END delete tree if possible
            # END handle force

            if not dry_run and os.path.isdir(git_dir):
                rmtree(git_dir)
            # end handle separate bare repository
        # END handle module deletion

        # void our data not to delay invalid access
        if not dry_run:
            self._clear_cache()

        # DELETE CONFIGURATION
        ######################
        if configuration and not dry_run:
            # first the index-entry
            parent_index = self.repo.index
            try:
                del(parent_index.entries[parent_index.entry_key(self.path, 0)])
            except __HOLE__:
                pass
            # END delete entry
            parent_index.write()

            # now git config - need the config intact, otherwise we can't query
            # information anymore
            writer = self.repo.config_writer()
            writer.remove_section(sm_section(self.name))
            writer.release()

            writer = self.config_writer()
            writer.remove_section()
            writer.release()
        # END delete configuration

        return self
dataset/ETHPy150Open gitpython-developers/GitPython/git/objects/submodule/base.py/Submodule.remove