asottile: Sourced a lot of the information from https://www.in-ulm.de/~mascheck/various/argmax/
diff --git a/pre_commit/main.py b/pre_commit/main.py
index a935cf1..be0fa7f 100644
--- a/pre_commit/main.py
+++ b/pre_commit/main.py
@@ -255,8 +255,7 @@ def main(argv=None):
         parser.parse_args(['--help'])
 
     with error_handler(), logging_handler(args.color):
-        if args.command not in {'clean', 'gc', 'sample-config'}:
-            _adjust_args_and_chdir(args)
+        _adjust_args_and_chdir(args)
 
         git.check_for_cygwin_mismatch()
 
diff --git a/pre_commit/xargs.py b/pre_commit/xargs.py
index bd9205b..a382759 100644
--- a/pre_commit/xargs.py
+++ b/pre_commit/xargs.py
@@ -5,6 +5,7 @@ from __future__ import unicode_literals
 import concurrent.futures
 import contextlib
 import math
+import os
 import sys
 
 import six
@@ -13,10 +14,24 @@ from pre_commit import parse_shebang
 from pre_commit.util import cmd_output
 
 
-# TODO: properly compute max_length value
-def _get_platform_max_length():
-    # posix minimum
-    return 4 * 1024
+def _environ_size(_env=None):
+    environ = _env if _env is not None else getattr(os, 'environb', os.environ)
+    size = 8 * len(environ)  # number of pointers in `envp`
+    for k, v in environ.items():
+        size += len(k) + len(v) + 2  # c strings in `envp`
+    return size
+
+
+def _get_platform_max_length():  # pragma: no cover (platform specific)
+    if os.name == 'posix':
+        maximum = os.sysconf(str('SC_ARG_MAX')) - 2048 - _environ_size()
+        maximum = min(maximum, 2 ** 17)
+        return maximum
+    elif os.name == 'nt':
+        return 2 ** 15 - 2048  # UNICODE_STRING max - headroom
+    else:
+        # posix minimum
+        return 2 ** 12
 
 
 def _command_length(*cmd):
@@ -52,7 +67,7 @@ def partition(cmd, varargs, target_concurrency, _max_length=None):
     # Reversed so arguments are in order
     varargs = list(reversed(varargs))
 
-    total_length = _command_length(*cmd)
+    total_length = _command_length(*cmd) + 1
     while varargs:
         arg = varargs.pop()
 
@@ -69,7 +84,7 @@ def partition(cmd, varargs, target_concurrency, _max_length=None):
             # We've exceeded the length, yield a command
             ret.append(cmd + tuple(ret_cmd))
             ret_cmd = []
-            total_length = _command_length(*cmd)
+            total_length = _command_length(*cmd) + 1
             varargs.append(arg)
 
     ret.append(cmd + tuple(ret_cmd))
@@ -99,7 +114,7 @@ def xargs(cmd, varargs, **kwargs):
     stderr = b''
 
     try:
-        parse_shebang.normexe(cmd[0])
+        cmd = parse_shebang.normalize_cmd(cmd)
     except parse_shebang.ExecutableNotFoundError as e:
         return e.to_output()
 

Improve platform command line length limits
I have a question related to #510 

When I run `pre-commit run` all hooks work as expected (processing just changed files), but `pre-commit run -a` divides a list of files into 5 bulks and run the same hook in parallel executions. This creates unnecessary checks of files which belong to the same directory.

Is it possible to control that certain hooks should not be executed in parallel but rather pass all filenames to it?

Alternatively, is there an environment variable or something like that which says that pre-commit is running a hook for all files?
diff --git a/tests/xargs_test.py b/tests/xargs_test.py
index 0e91f9b..a6cffd7 100644
--- a/tests/xargs_test.py
+++ b/tests/xargs_test.py
@@ -10,9 +10,24 @@ import mock
 import pytest
 import six
 
+from pre_commit import parse_shebang
 from pre_commit import xargs
 
 
+@pytest.mark.parametrize(
+    ('env', 'expected'),
+    (
+        ({}, 0),
+        ({b'x': b'1'}, 12),
+        ({b'x': b'12'}, 13),
+        ({b'x': b'1', b'y': b'2'}, 24),
+    ),
+)
+def test_environ_size(env, expected):
+    # normalize integer sizing
+    assert xargs._environ_size(_env=env) == expected
+
+
 @pytest.fixture
 def win32_py2_mock():
     with mock.patch.object(sys, 'getfilesystemencoding', return_value='utf-8'):
@@ -56,7 +71,7 @@ def test_partition_limits():
             '.' * 6,
         ),
         1,
-        _max_length=20,
+        _max_length=21,
     )
     assert ret == (
         ('ninechars', '.' * 5, '.' * 4),
@@ -70,21 +85,21 @@ def test_partition_limit_win32_py3(win32_py3_mock):
     cmd = ('ninechars',)
     # counted as half because of utf-16 encode
     varargs = ('😑' * 5,)
-    ret = xargs.partition(cmd, varargs, 1, _max_length=20)
+    ret = xargs.partition(cmd, varargs, 1, _max_length=21)
     assert ret == (cmd + varargs,)
 
 
 def test_partition_limit_win32_py2(win32_py2_mock):
     cmd = ('ninechars',)
     varargs = ('😑' * 5,)  # 4 bytes * 5
-    ret = xargs.partition(cmd, varargs, 1, _max_length=30)
+    ret = xargs.partition(cmd, varargs, 1, _max_length=31)
     assert ret == (cmd + varargs,)
 
 
 def test_partition_limit_linux(linux_mock):
     cmd = ('ninechars',)
     varargs = ('😑' * 5,)
-    ret = xargs.partition(cmd, varargs, 1, _max_length=30)
+    ret = xargs.partition(cmd, varargs, 1, _max_length=31)
     assert ret == (cmd + varargs,)
 
 
@@ -134,9 +149,9 @@ def test_xargs_smoke():
     assert err == b''
 
 
-exit_cmd = ('bash', '-c', 'exit $1', '--')
+exit_cmd = parse_shebang.normalize_cmd(('bash', '-c', 'exit $1', '--'))
 # Abuse max_length to control the exit code
-max_length = len(' '.join(exit_cmd)) + 2
+max_length = len(' '.join(exit_cmd)) + 3
 
 
 def test_xargs_negate():
@@ -165,14 +180,14 @@ def test_xargs_retcode_normal():
 
 
 def test_xargs_concurrency():
-    bash_cmd = ('bash', '-c')
+    bash_cmd = parse_shebang.normalize_cmd(('bash', '-c'))
     print_pid = ('sleep 0.5 && echo $$',)
 
     start = time.time()
     ret, stdout, _ = xargs.xargs(
         bash_cmd, print_pid * 5,
         target_concurrency=5,
-        _max_length=len(' '.join(bash_cmd + print_pid)),
+        _max_length=len(' '.join(bash_cmd + print_pid)) + 1,
     )
     elapsed = time.time() - start
     assert ret == 0

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest pytest-cov pytest-xdist pytest-mock pytest-asyncio
apt-get update apt-get install -y gcc curl -sSf https://sh.rustup.rs | bash -s -- -y export PATH=$HOME/.cargo/bin:$PATH
3.7
requirements-dev.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
aspy.yaml==1.3.0
certifi @ file:///croot/certifi_1671487769961/work/certifi
cfgv==3.3.1
coverage==7.2.7
distlib==0.3.9
exceptiongroup==1.2.2
execnet==2.0.2
filelock==3.12.2
flake8==5.0.4
identify==2.5.24
importlib-metadata==6.7.0
iniconfig==2.0.0
mccabe==0.7.0
mock==5.2.0
nodeenv==1.9.1
packaging==24.0
platformdirs==4.0.0
pluggy==1.2.0
-e git+https://github.com/pre-commit/pre-commit.git@cac1a3f34e62e440d9eb187bd2a321aed472860e#egg=pre_commit
pycodestyle==2.9.1
pyflakes==2.5.0
pytest==7.4.4
pytest-asyncio==0.21.2
pytest-cov==4.1.0
pytest-env==1.0.1
pytest-mock==3.11.1
pytest-xdist==3.5.0
PyYAML==6.0.1
six==1.17.0
toml==0.10.2
tomli==2.0.1
typing_extensions==4.7.1
virtualenv==20.26.6
zipp==3.15.0

name: pre-commit
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2022.12.7=py37h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=22.3.1=py37h06a4308_0
  - python=3.7.16=h7a1cb2a_0
  - readline=8.2=h5eee18b_0
  - setuptools=65.6.3=py37h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.38.4=py37h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - aspy-yaml==1.3.0
      - cfgv==3.3.1
      - coverage==7.2.7
      - distlib==0.3.9
      - exceptiongroup==1.2.2
      - execnet==2.0.2
      - filelock==3.12.2
      - flake8==5.0.4
      - identify==2.5.24
      - importlib-metadata==6.7.0
      - iniconfig==2.0.0
      - mccabe==0.7.0
      - mock==5.2.0
      - nodeenv==1.9.1
      - packaging==24.0
      - platformdirs==4.0.0
      - pluggy==1.2.0
      - pycodestyle==2.9.1
      - pyflakes==2.5.0
      - pytest==7.4.4
      - pytest-asyncio==0.21.2
      - pytest-cov==4.1.0
      - pytest-env==1.0.1
      - pytest-mock==3.11.1
      - pytest-xdist==3.5.0
      - pyyaml==6.0.1
      - six==1.17.0
      - toml==0.10.2
      - tomli==2.0.1
      - typing-extensions==4.7.1
      - virtualenv==20.26.6
      - zipp==3.15.0
prefix: /opt/conda/envs/pre-commit

tests/xargs_test.py::test_environ_size[env0-0] tests/xargs_test.py::test_environ_size[env1-12] tests/xargs_test.py::test_environ_size[env2-13] tests/xargs_test.py::test_environ_size[env3-24]
tests/xargs_test.py::test_partition_trivial tests/xargs_test.py::test_partition_simple tests/xargs_test.py::test_partition_limits tests/xargs_test.py::test_partition_limit_win32_py3 tests/xargs_test.py::test_partition_limit_win32_py2 tests/xargs_test.py::test_partition_limit_linux tests/xargs_test.py::test_argument_too_long_with_large_unicode tests/xargs_test.py::test_partition_target_concurrency tests/xargs_test.py::test_partition_target_concurrency_wont_make_tiny_partitions tests/xargs_test.py::test_argument_too_long tests/xargs_test.py::test_xargs_smoke tests/xargs_test.py::test_xargs_negate tests/xargs_test.py::test_xargs_negate_command_not_found tests/xargs_test.py::test_xargs_retcode_normal tests/xargs_test.py::test_xargs_concurrency tests/xargs_test.py::test_thread_mapper_concurrency_uses_threadpoolexecutor_map tests/xargs_test.py::test_thread_mapper_concurrency_uses_regular_map
pre_commit/xargs.py pre_commit/main.py
pre_commit/xargs.py pre_commit/main.py