.. versionadded:: 2015.8.12,2016.3.3,2016.11.0

    Interface to `git-diff(1)`_

    cwd
        The path to the git checkout

    item1 and item2
        Revision(s) to pass to the ``git diff`` command. One or both of these
        arguments may be ignored if some of the options below are set to
        ``True``. When ``cached`` is ``False``, and no revisions are passed
        to this function, then the current working tree will be compared
        against the index (i.e. unstaged changes). When two revisions are
        passed, they will be compared to each other.

    opts
        Any additional options to add to the command line, in a single string

        .. note::
            On the Salt CLI, if the opts are preceded with a dash, it is
            necessary to precede them with ``opts=`` (as in the CLI examples
            below) to avoid causing errors with Salt's own argument parsing.

    git_opts
        Any additional options to add to git command itself (not the ``diff``
        subcommand), in a single string. This is useful for passing ``-c`` to
        run git with temporary changes to the git configuration.

        .. versionadded:: 2017.7.0

        .. note::
            This is only supported in git 1.7.2 and newer.

    user
        User under which to run the git command. By default, the command is run
        by the user under which the minion is running.

    password
        Windows only. Required when specifying ``user``. This parameter will be
        ignored on non-Windows platforms.

      .. versionadded:: 2016.3.4

    no_index : False
        When it is necessary to diff two files in the same repo against each
        other, and not diff two different revisions, set this option to
        ``True``. If this is left ``False`` in these instances, then a normal
        ``git diff`` will be performed against the index (i.e. unstaged
        changes), and files in the ``paths`` option will be used to narrow down
        the diff output.

        .. note::
            Requires Git 1.5.1 or newer. Additionally, when set to ``True``,
            ``item1`` and ``item2`` will be ignored.

    cached : False
        If ``True``, compare staged changes to ``item1`` (if specified),
        otherwise compare them to the most recent commit.

        .. note::
            ``item2`` is ignored if this option is is set to ``True``.

    paths
        File paths to pass to the ``git diff`` command. Can be passed as a
        comma-separated list or a Python list.

    output_encoding
        Use this option to specify which encoding to use to decode the output
        from any git commands which are run. This should not be needed in most
        cases.

        .. note::
            This should only be needed if the files in the repository were
            created with filenames using an encoding other than UTF-8 to handle
            Unicode characters.

        .. versionadded:: 2018.3.1

    .. _`git-diff(1)`: http://git-scm.com/docs/git-diff

    CLI Example:

    .. code-block:: bash

        # Perform diff against the index (staging area for next commit)
        salt myminion git.diff /path/to/repo
        # Compare staged changes to the most recent commit
        salt myminion git.diff /path/to/repo cached=True
        # Compare staged changes to a specific revision
        salt myminion git.diff /path/to/repo mybranch cached=True
        # Perform diff against the most recent commit (includes staged changes)
        salt myminion git.diff /path/to/repo HEAD
        # Diff two commits
        salt myminion git.diff /path/to/repo abcdef1 aabbccd
        # Diff two commits, only showing differences in the specified paths
        salt myminion git.diff /path/to/repo abcdef1 aabbccd paths=path/to/file1,path/to/file2
        # Diff two files with one being outside the working tree
        salt myminion git.diff /path/to/repo no_index=True paths=path/to/file1,/absolute/path/to/file2

def diff(cwd,
         item1=None,
         item2=None,
         opts='',
         git_opts='',
         user=None,
         password=None,
         no_index=False,
         cached=False,
         paths=None,
         output_encoding=None):
    '''
    .. versionadded:: 2015.8.12,2016.3.3,2016.11.0

    Interface to `git-diff(1)`_

    cwd
        The path to the git checkout

    item1 and item2
        Revision(s) to pass to the ``git diff`` command. One or both of these
        arguments may be ignored if some of the options below are set to
        ``True``. When ``cached`` is ``False``, and no revisions are passed
        to this function, then the current working tree will be compared
        against the index (i.e. unstaged changes). When two revisions are
        passed, they will be compared to each other.

    opts
        Any additional options to add to the command line, in a single string

        .. note::
            On the Salt CLI, if the opts are preceded with a dash, it is
            necessary to precede them with ``opts=`` (as in the CLI examples
            below) to avoid causing errors with Salt's own argument parsing.

    git_opts
        Any additional options to add to git command itself (not the ``diff``
        subcommand), in a single string. This is useful for passing ``-c`` to
        run git with temporary changes to the git configuration.

        .. versionadded:: 2017.7.0

        .. note::
            This is only supported in git 1.7.2 and newer.

    user
        User under which to run the git command. By default, the command is run
        by the user under which the minion is running.

    password
        Windows only. Required when specifying ``user``. This parameter will be
        ignored on non-Windows platforms.

      .. versionadded:: 2016.3.4

    no_index : False
        When it is necessary to diff two files in the same repo against each
        other, and not diff two different revisions, set this option to
        ``True``. If this is left ``False`` in these instances, then a normal
        ``git diff`` will be performed against the index (i.e. unstaged
        changes), and files in the ``paths`` option will be used to narrow down
        the diff output.

        .. note::
            Requires Git 1.5.1 or newer. Additionally, when set to ``True``,
            ``item1`` and ``item2`` will be ignored.

    cached : False
        If ``True``, compare staged changes to ``item1`` (if specified),
        otherwise compare them to the most recent commit.

        .. note::
            ``item2`` is ignored if this option is is set to ``True``.

    paths
        File paths to pass to the ``git diff`` command. Can be passed as a
        comma-separated list or a Python list.

    output_encoding
        Use this option to specify which encoding to use to decode the output
        from any git commands which are run. This should not be needed in most
        cases.

        .. note::
            This should only be needed if the files in the repository were
            created with filenames using an encoding other than UTF-8 to handle
            Unicode characters.

        .. versionadded:: 2018.3.1

    .. _`git-diff(1)`: http://git-scm.com/docs/git-diff

    CLI Example:

    .. code-block:: bash

        # Perform diff against the index (staging area for next commit)
        salt myminion git.diff /path/to/repo
        # Compare staged changes to the most recent commit
        salt myminion git.diff /path/to/repo cached=True
        # Compare staged changes to a specific revision
        salt myminion git.diff /path/to/repo mybranch cached=True
        # Perform diff against the most recent commit (includes staged changes)
        salt myminion git.diff /path/to/repo HEAD
        # Diff two commits
        salt myminion git.diff /path/to/repo abcdef1 aabbccd
        # Diff two commits, only showing differences in the specified paths
        salt myminion git.diff /path/to/repo abcdef1 aabbccd paths=path/to/file1,path/to/file2
        # Diff two files with one being outside the working tree
        salt myminion git.diff /path/to/repo no_index=True paths=path/to/file1,/absolute/path/to/file2
    '''
    if no_index and cached:
        raise CommandExecutionError(
            'The \'no_index\' and \'cached\' options cannot be used together'
        )

    command = ['git'] + _format_git_opts(git_opts)
    command.append('diff')
    command.extend(_format_opts(opts))

    if paths is not None and not isinstance(paths, (list, tuple)):
        try:
            paths = paths.split(',')
        except AttributeError:
            paths = six.text_type(paths).split(',')

    ignore_retcode = False
    failhard = True

    if no_index:
        if _LooseVersion(version(versioninfo=False)) < _LooseVersion('1.5.1'):
            raise CommandExecutionError(
                'The \'no_index\' option is only supported in Git 1.5.1 and '
                'newer'
            )
        ignore_retcode = True
        failhard = False
        command.append('--no-index')
        for value in [x for x in (item1, item2) if x]:
            log.warning(
                'Revision \'%s\' ignored in git diff, as revisions cannot be '
                'used when no_index=True', value
            )

    elif cached:
        command.append('--cached')
        if item1:
            command.append(item1)
        if item2:
            log.warning(
                'Second revision \'%s\' ignored in git diff, at most one '
                'revision is considered when cached=True', item2
            )

    else:
        for value in [x for x in (item1, item2) if x]:
            command.append(value)

    if paths:
        command.append('--')
        command.extend(paths)

    return _git_run(command,
                    cwd=cwd,
                    user=user,
                    password=password,
                    ignore_retcode=ignore_retcode,
                    failhard=failhard,
                    redirect_stderr=True,
                    output_encoding=output_encoding)['stdout']