diff --git a/.pre-commit-config-all.yaml b/.pre-commit-config-all.yaml
index 98829e25fc37fba06200c98f2540d175ca8c5ad6..3910835ae9d6a71cefadcba1e2b040d49a0e805d 100644
--- a/.pre-commit-config-all.yaml
+++ b/.pre-commit-config-all.yaml
@@ -19,12 +19,12 @@ repos:
           - --quiet
         files: ^((homeassistant|script|tests)/.+)?[^/]+\.py$
 -   repo: https://gitlab.com/pycqa/flake8
-    rev: 3.7.8
+    rev: 3.7.9
     hooks:
     -   id: flake8
         additional_dependencies:
-          - flake8-docstrings==1.3.1
-          - pydocstyle==4.0.0
+          - flake8-docstrings==1.5.0
+          - pydocstyle==4.0.1
         files: ^(homeassistant|script|tests)/.+\.py$
 # Using a local "system" mypy instead of the mypy hook, because its
 # results depend on what is installed. And the mypy hook runs in a
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 4beff14965b9ced26bbb6a38533186ce0d783e78..3220ac848668910b871a02506512bfc8c9f9d9d6 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -15,10 +15,10 @@ repos:
           - --quiet
         files: ^((homeassistant|script|tests)/.+)?[^/]+\.py$
 -   repo: https://gitlab.com/pycqa/flake8
-    rev: 3.7.8
+    rev: 3.7.9
     hooks:
     -   id: flake8
         additional_dependencies:
-          - flake8-docstrings==1.3.1
-          - pydocstyle==4.0.0
+          - flake8-docstrings==1.5.0
+          - pydocstyle==4.0.1
         files: ^(homeassistant|script|tests)/.+\.py$
diff --git a/requirements_test.txt b/requirements_test.txt
index 06a2ef1621d26eff7fd073e6cf3d34c9a196d4aa..33fab3d6c6af1da4e43844c7f7c8517fdc7cd9e2 100644
--- a/requirements_test.txt
+++ b/requirements_test.txt
@@ -2,16 +2,12 @@
 # make new things fail. Manually update these pins when pulling in a
 # new version
 
-# When updating this file, update .pre-commit-config*.yaml too
+-r requirements_test_pre_commit.txt
 asynctest==0.13.0
-black==19.10b0
 codecov==2.0.15
-flake8-docstrings==1.5.0
-flake8==3.7.8
 mock-open==1.3.1
 mypy==0.740
 pre-commit==1.20.0
-pydocstyle==4.0.1
 pylint==2.4.3
 astroid==2.3.2
 pytest-aiohttp==0.3.0
diff --git a/requirements_test_all.txt b/requirements_test_all.txt
index 9395c0cefadbe2b43a4852b0fd7d5e233a30ebf0..2a9b30d3e4f6b7533cf8ef03905fe5eb73074cfc 100644
--- a/requirements_test_all.txt
+++ b/requirements_test_all.txt
@@ -1,28 +1,7 @@
-# Home Assistant test
-# linters such as flake8 and pylint should be pinned, as new releases
-# make new things fail. Manually update these pins when pulling in a
-# new version
-
-# When updating this file, update .pre-commit-config*.yaml too
-asynctest==0.13.0
-black==19.10b0
-codecov==2.0.15
-flake8-docstrings==1.5.0
-flake8==3.7.8
-mock-open==1.3.1
-mypy==0.740
-pre-commit==1.20.0
-pydocstyle==4.0.1
-pylint==2.4.3
-astroid==2.3.2
-pytest-aiohttp==0.3.0
-pytest-cov==2.8.1
-pytest-sugar==0.9.2
-pytest-timeout==1.3.3
-pytest==5.2.2
-requests_mock==1.7.0
-responses==0.10.6
+# Home Assistant tests, full dependency set
+# Automatically generated by gen_requirements_all.py, do not edit
 
+-r requirements_test.txt
 
 # homeassistant.components.homekit
 HAP-python==2.6.0
diff --git a/requirements_test_pre_commit.txt b/requirements_test_pre_commit.txt
new file mode 100644
index 0000000000000000000000000000000000000000..29380ca7cd28be6b93c224685e160ff7ec56b1e0
--- /dev/null
+++ b/requirements_test_pre_commit.txt
@@ -0,0 +1,6 @@
+# Automatically generated from .pre-commit-config-all.yaml by gen_requirements_all.py, do not edit
+
+black==19.10b0
+flake8-docstrings==1.5.0
+flake8==3.7.9
+pydocstyle==4.0.1
diff --git a/script/gen_requirements_all.py b/script/gen_requirements_all.py
index 930ffa11b5f2cd633cf2c7df4a36a7cc6d428d88..9bbe7d379ec29efe6b0fa943cd0e7f0e084c2193 100755
--- a/script/gen_requirements_all.py
+++ b/script/gen_requirements_all.py
@@ -8,6 +8,8 @@ import pkgutil
 import re
 import sys
 
+from homeassistant.util.yaml.loader import load_yaml
+
 from script.hassfest.model import Integration
 
 COMMENT_REQUIREMENTS = (
@@ -225,10 +227,11 @@ def requirements_all_output(reqs):
 def requirements_test_output(reqs):
     """Generate output for test_requirements."""
     output = []
-    output.append("# Home Assistant test")
-    output.append("\n")
-    output.append(Path("requirements_test.txt").read_text())
-    output.append("\n")
+    output.append("# Home Assistant tests, full dependency set\n")
+    output.append(
+        f"# Automatically generated by {Path(__file__).name}, do not edit\n\n"
+    )
+    output.append("-r requirements_test.txt\n")
 
     filtered = {
         requirement: modules
@@ -246,6 +249,24 @@ def requirements_test_output(reqs):
     return "".join(output)
 
 
+def requirements_pre_commit_output():
+    """Generate output for pre-commit dependencies."""
+    source = ".pre-commit-config-all.yaml"
+    pre_commit_conf = load_yaml(source)
+    reqs = []
+    for repo in (x for x in pre_commit_conf["repos"] if x.get("rev")):
+        for hook in repo["hooks"]:
+            reqs.append(f"{hook['id']}=={repo['rev']}")
+            reqs.extend(x for x in hook.get("additional_dependencies", ()))
+    output = [
+        f"# Automatically generated "
+        f"from {source} by {Path(__file__).name}, do not edit",
+        "",
+    ]
+    output.extend(sorted(reqs))
+    return "\n".join(output) + "\n"
+
+
 def gather_constraints():
     """Construct output for constraint file."""
     return (
@@ -285,10 +306,12 @@ def main(validate):
 
     reqs_file = requirements_all_output(data)
     reqs_test_file = requirements_test_output(data)
+    reqs_pre_commit_file = requirements_pre_commit_output()
     constraints = gather_constraints()
 
     files = (
         ("requirements_all.txt", reqs_file),
+        ("requirements_test_pre_commit.txt", reqs_pre_commit_file),
         ("requirements_test_all.txt", reqs_test_file),
         ("homeassistant/package_constraints.txt", constraints),
     )