Repository: pre-commit/pre-commit

Issue:
try-repo with unstaged commits sometimes doesn't work
```
$ git status
On branch pre_commit
Your branch is up to date with 'origin/master'.

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	new file:   .pre-commit-hooks.yaml

Untracked files:
  (use "git add <file>..." to include in what will be committed)

	build/
	dist/
```

```
$ pre-commit try-repo ../setup-cfg-fmt/
[WARNING] Creating temporary repo with uncommitted changes...
An unexpected error has occurred: CalledProcessError: Command: ('/usr/bin/git', 'commit', '--no-edit', '--no-gpg-sign', '-n', '-minit')
Return code: 1
Expected return code: 0
Output: 
    On branch _pc_tmp
    nothing to commit, working tree clean
    
Errors: (none)

Check the log at /home/asottile/.cache/pre-commit/pre-commit.log
```

```
$ cat /home/asottile/.cache/pre-commit/pre-commit.log
An unexpected error has occurred: CalledProcessError: Command: ('/usr/bin/git', 'commit', '--no-edit', '--no-gpg-sign', '-n', '-minit')
Return code: 1
Expected return code: 0
Output: 
    On branch _pc_tmp
    nothing to commit, working tree clean
    
Errors: (none)

Traceback (most recent call last):
  File "/home/asottile/opt/venv/lib/python3.6/site-packages/pre_commit/error_handler.py", line 46, in error_handler
    yield
  File "/home/asottile/opt/venv/lib/python3.6/site-packages/pre_commit/main.py", line 295, in main
    return try_repo(args)
  File "/home/asottile/opt/venv/lib/python3.6/site-packages/pre_commit/commands/try_repo.py", line 48, in try_repo
    repo, ref = _repo_ref(tempdir, args.repo, args.ref)
  File "/home/asottile/opt/venv/lib/python3.6/site-packages/pre_commit/commands/try_repo.py", line 39, in _repo_ref
    git.commit(repo=shadow)
  File "/home/asottile/opt/venv/lib/python3.6/site-packages/pre_commit/git.py", line 143, in commit
    cmd_output(*cmd, cwd=repo, env=env)
  File "/home/asottile/opt/venv/lib/python3.6/site-packages/pre_commit/util.py", line 153, in cmd_output
    returncode, cmd, retcode, output=(stdout, stderr),
pre_commit.util.CalledProcessError: Command: ('/usr/bin/git', 'commit', '--no-edit', '--no-gpg-sign', '-n', '-minit')
Return code: 1
Expected return code: 0
Output: 
    On branch _pc_tmp
    nothing to commit, working tree clean
    
Errors: (none)
```


Discussion:

Resolving patch:
diff --git a/pre_commit/commands/try_repo.py b/pre_commit/commands/try_repo.py
--- a/pre_commit/commands/try_repo.py
+++ b/pre_commit/commands/try_repo.py
@@ -15,6 +15,7 @@
 from pre_commit.store import Store
 from pre_commit.util import cmd_output
 from pre_commit.util import tmpdir
+from pre_commit.xargs import xargs
 
 logger = logging.getLogger(__name__)
 
@@ -32,9 +33,15 @@ def _repo_ref(tmpdir, repo, ref):
         shadow = os.path.join(tmpdir, 'shadow-repo')
         cmd_output('git', 'clone', repo, shadow)
         cmd_output('git', 'checkout', ref, '-b', '_pc_tmp', cwd=shadow)
+
         idx = git.git_path('index', repo=shadow)
         objs = git.git_path('objects', repo=shadow)
         env = dict(os.environ, GIT_INDEX_FILE=idx, GIT_OBJECT_DIRECTORY=objs)
+
+        staged_files = git.get_staged_files(cwd=repo)
+        if staged_files:
+            xargs(('git', 'add', '--'), staged_files, cwd=repo, env=env)
+
         cmd_output('git', 'add', '-u', cwd=repo, env=env)
         git.commit(repo=shadow)
 
diff --git a/pre_commit/git.py b/pre_commit/git.py
--- a/pre_commit/git.py
+++ b/pre_commit/git.py
@@ -91,11 +91,12 @@ def get_conflicted_files():
     return set(merge_conflict_filenames) | set(merge_diff_filenames)
 
 
-def get_staged_files():
+def get_staged_files(cwd=None):
     return zsplit(cmd_output(
         'git', 'diff', '--staged', '--name-only', '--no-ext-diff', '-z',
         # Everything except for D
         '--diff-filter=ACMRTUXB',
+        cwd=cwd,
     )[1])
 
 
diff --git a/pre_commit/xargs.py b/pre_commit/xargs.py
--- a/pre_commit/xargs.py
+++ b/pre_commit/xargs.py
@@ -109,6 +109,7 @@ def xargs(cmd, varargs, **kwargs):
     """
     negate = kwargs.pop('negate', False)
     target_concurrency = kwargs.pop('target_concurrency', 1)
+    max_length = kwargs.pop('_max_length', _get_platform_max_length())
     retcode = 0
     stdout = b''
     stderr = b''
@@ -118,10 +119,10 @@ def xargs(cmd, varargs, **kwargs):
     except parse_shebang.ExecutableNotFoundError as e:
         return e.to_output()
 
-    partitions = partition(cmd, varargs, target_concurrency, **kwargs)
+    partitions = partition(cmd, varargs, target_concurrency, max_length)
 
     def run_cmd_partition(run_cmd):
-        return cmd_output(*run_cmd, encoding=None, retcode=None)
+        return cmd_output(*run_cmd, encoding=None, retcode=None, **kwargs)
 
     threads = min(len(partitions), target_concurrency)
     with _thread_mapper(threads) as thread_map:


Test patch:
diff --git a/tests/commands/try_repo_test.py b/tests/commands/try_repo_test.py
--- a/tests/commands/try_repo_test.py
+++ b/tests/commands/try_repo_test.py
@@ -123,3 +123,15 @@ def test_try_repo_uncommitted_changes(cap_out, tempdir_factory):
         config,
     )
     assert rest == 'modified name!...........................................................Passed\n'  # noqa: E501
+
+
+def test_try_repo_staged_changes(tempdir_factory):
+    repo = make_repo(tempdir_factory, 'modified_file_returns_zero_repo')
+
+    with cwd(repo):
+        open('staged-file', 'a').close()
+        open('second-staged-file', 'a').close()
+        cmd_output('git', 'add', '.')
+
+    with cwd(git_dir(tempdir_factory)):
+        assert not try_repo(try_repo_opts(repo, hook='bash_hook'))
diff --git a/tests/xargs_test.py b/tests/xargs_test.py
--- a/tests/xargs_test.py
+++ b/tests/xargs_test.py
@@ -208,3 +208,13 @@ def test_thread_mapper_concurrency_uses_threadpoolexecutor_map():
 def test_thread_mapper_concurrency_uses_regular_map():
     with xargs._thread_mapper(1) as thread_map:
         assert thread_map is map
+
+
+def test_xargs_propagate_kwargs_to_cmd():
+    env = {'PRE_COMMIT_TEST_VAR': 'Pre commit is awesome'}
+    cmd = ('bash', '-c', 'echo $PRE_COMMIT_TEST_VAR', '--')
+    cmd = parse_shebang.normalize_cmd(cmd)
+
+    ret, stdout, _ = xargs.xargs(cmd, ('1',), env=env)
+    assert ret == 0
+    assert b'Pre commit is awesome' in stdout