def move(
        self,
        items: Union[PathLike, Sequence[Union[PathLike, Blob, BaseIndexEntry, "Submodule"]]],
        skip_errors: bool = False,
        **kwargs: Any,
    ) -> List[Tuple[str, str]]:
        """Rename/move the items, whereas the last item is considered the destination of
        the move operation.

        If the destination is a file, the first item (of two) must be a file as well.

        If the destination is a directory, it may be preceded by one or more directories
        or files.

        The working tree will be affected in non-bare repositories.

        :param items:
            Multiple types of items are supported, please see the :meth:`remove` method
            for reference.

        :param skip_errors:
            If ``True``, errors such as ones resulting from missing source files will be
            skipped.

        :param kwargs:
            Additional arguments you would like to pass to :manpage:`git-mv(1)`, such as
            ``dry_run`` or ``force``.

        :return:
            List(tuple(source_path_string, destination_path_string), ...)

            A list of pairs, containing the source file moved as well as its actual
            destination. Relative to the repository root.

        :raise ValueError:
            If only one item was given.

        :raise git.exc.GitCommandError:
            If git could not handle your request.
        """
        args = []
        if skip_errors:
            args.append("-k")

        paths = self._items_to_rela_paths(items)
        if len(paths) < 2:
            raise ValueError("Please provide at least one source and one destination of the move operation")

        was_dry_run = kwargs.pop("dry_run", kwargs.pop("n", None))
        kwargs["dry_run"] = True

        # First execute rename in dry run so the command tells us what it actually does
        # (for later output).
        out = []
        mvlines = self.repo.git.mv(args, paths, **kwargs).splitlines()

        # Parse result - first 0:n/2 lines are 'checking ', the remaining ones are the
        # 'renaming' ones which we parse.
        for ln in range(int(len(mvlines) / 2), len(mvlines)):
            tokens = mvlines[ln].split(" to ")
            assert len(tokens) == 2, "Too many tokens in %s" % mvlines[ln]

            # [0] = Renaming x
            # [1] = y
            out.append((tokens[0][9:], tokens[1]))
        # END for each line to parse

        # Either prepare for the real run, or output the dry-run result.
        if was_dry_run:
            return out
        # END handle dry run

        # Now apply the actual operation.
        kwargs.pop("dry_run")
        self.repo.git.mv(args, paths, **kwargs)

        return out
Rename/move the items, whereas the last item is considered the destination of
        the move operation.

        If the destination is a file, the first item (of two) must be a file as well.

        If the destination is a directory, it may be preceded by one or more directories
        or files.

        The working tree will be affected in non-bare repositories.

        :param items:
            Multiple types of items are supported, please see the :meth:`remove` method
            for reference.

        :param skip_errors:
            If ``True``, errors such as ones resulting from missing source files will be
            skipped.

        :param kwargs:
            Additional arguments you would like to pass to :manpage:`git-mv(1)`, such as
            ``dry_run`` or ``force``.

        :return:
            List(tuple(source_path_string, destination_path_string), ...)

            A list of pairs, containing the source file moved as well as its actual
            destination. Relative to the repository root.

        :raise ValueError:
            If only one item was given.

        :raise git.exc.GitCommandError:
            If git could not handle your request.
        
git/index/base.py