# Buggy code
def staged_files_only(cmd_runner):
    """Clear any unstaged changes from the git working directory inside this
    context.

    Args:
        cmd_runner - PrefixedCommandRunner
    """
    # Determine if there are unstaged files
    retcode, diff_stdout, _ = cmd_runner.run(
        ["git", "diff", "--ignore-submodules", "--binary", "--exit-code"],
        retcode=None,
    )
    if retcode and diff_stdout.strip():
        patch_filename = cmd_runner.path("patch{0}".format(int(time.time())))
        logger.warning("Unstaged files detected.")
        logger.info(
            "Stashing unstaged files to {0}.".format(patch_filename),
        )
        # Save the current unstaged changes as a patch
        with open(patch_filename, "w") as patch_file:
            patch_file.write(diff_stdout)

        # Clear the working directory of unstaged changes
        cmd_runner.run(["git", "checkout", "--", "."])
        try:
            yield
        finally:
            # Try to apply the patch we saved
            try:
                cmd_runner.run(["git", "apply", patch_filename])
            except CalledProcessError:
                logger.warning(
                    "Stashed changes conflicted with hook auto-fixes... "
                    "Rolling back fixes..."
                )
                # We failed to apply the patch, presumably due to fixes made
                # by hooks.
                # Roll back the changes made by hooks.
                cmd_runner.run(["git", "checkout", "--", "."])
                cmd_runner.run(["git", "apply", patch_filename])
            logger.info("Restored changes from {0}.".format(patch_filename))
    else:
        # There weren't any staged files so we don't need to do anything
        # special
        yield


# Traceback (UnicodeEncodeError)
$ pre-commit
[WARNING] Unstaged files detected.
[INFO] Stashing unstaged files to .../.pre-commit-files/patch1397853050.
Traceback (most recent call last):
File ".../bin/pre-commit", line 9, in <module>
load_entry_point('pre-commit==0.0.0', 'console_scripts', 'pre-commit')()
File ".../lib/python2.6/site-packages/pre_commit/util.py", line 52, in wrapper
return func(argv)
File ".../lib/python2.6/site-packages/pre_commit/run.py", line 59, in run
return commands.run(runner, args)
File ".../lib/python2.6/site-packages/pre_commit/commands.py", line 254, in run
with ctx:
File "/usr/lib64/python2.6/contextlib.py", line 16, in __enter__
return self.gen.next()
File ".../lib/python2.6/site-packages/pre_commit/staged_files_only.py", line 32, in staged_files_only
patch_file.write(diff_stdout)
UnicodeEncodeError: 'ascii' codec can't encode character u'\xfc' in position 3795: ordinal not in range(128)

# Fixed code
def staged_files_only(cmd_runner):
    """Clear any unstaged changes from the git working directory inside this
    context.

    Args:
        cmd_runner - PrefixedCommandRunner
    """
    # Determine if there are unstaged files
    retcode, diff_stdout, _ = cmd_runner.run(
        ["git", "diff", "--ignore-submodules", "--binary", "--exit-code"],
        retcode=None,
    )
    if retcode and diff_stdout.strip():
        patch_filename = cmd_runner.path("patch{0}".format(int(time.time())))
        logger.warning("Unstaged files detected.")
        logger.info(
            "Stashing unstaged files to {0}.".format(patch_filename),
        )
        # Save the current unstaged changes as a patch
        with io.open(patch_filename, "w", encoding="utf-8") as patch_file:
            patch_file.write(diff_stdout)

        # Clear the working directory of unstaged changes
        cmd_runner.run(["git", "checkout", "--", "."])
        try:
            yield
        finally:
            # Try to apply the patch we saved
            try:
                cmd_runner.run(["git", "apply", patch_filename])
            except CalledProcessError:
                logger.warning(
                    "Stashed changes conflicted with hook auto-fixes... "
                    "Rolling back fixes..."
                )
                # We failed to apply the patch, presumably due to fixes made
                # by hooks.
                # Roll back the changes made by hooks.
                cmd_runner.run(["git", "checkout", "--", "."])
                cmd_runner.run(["git", "apply", patch_filename])
            logger.info("Restored changes from {0}.".format(patch_filename))
    else:
        # There weren't any staged files so we don't need to do anything
        # special
        yield