{"id":45,"date":"2026-08-11T15:00:14","date_gmt":"2026-08-11T20:00:14","guid":{"rendered":"https:\/\/jcshort.net\/?p=45"},"modified":"2026-08-11T15:08:39","modified_gmt":"2026-08-11T20:08:39","slug":"global-git-hooks","status":"publish","type":"post","link":"https:\/\/jcshort.net\/?p=45","title":{"rendered":"Global git hooks"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Every once in a while, you&#8217;ll encounter a repository that ships its own hooks and think &#8220;I should do that for all my repos too!&#8221;, except you never quite get around to it, because there are dozens of repositories in play, some of them are low-traffic while others have esoteric linter configurations.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">But what about shared hooks, defined once in your global gitconfig, with a hook runner that&#8217;s smart enough to selectively invoke runners based on file types within the delta?  That&#8217;s a much faster way to cover every repo <em>no matter what<\/em>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Enter <a href=\"https:\/\/github.com\/evilmartians\/lefthook\">lefthook<\/a>.  But also <a href=\"https:\/\/pre-commit.com\">pre-commit<\/a>.  And whatever other hook manager you want to wrap.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Lefthook sits in the global gitconfig:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"Bash\" data-shcb-language-slug=\"bash\"><span><code lang=\"bash\" class=\"hljs language-bash language-bash\">$ git config get --global core.hooksPath\n~\/dotfiles\/git\/hooks\/global<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Bash<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">bash<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Lefthook, like most runners, provides opinionated default scripts and assumes it&#8217;s being installed in an individual repository.  It&#8217;s flexible enough to listen when told that its defaults are not required.  I use a single multicall script with symlinks for the actions I want to hook &#8211; primarily pre-commit and pre-push:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"Bash\" data-shcb-language-slug=\"bash\"><span><code lang=\"bash\" class=\"hljs language-bash language-bash\"><span class=\"hljs-meta\">#!\/usr\/bin\/env bash\n<\/span>\n<span class=\"hljs-built_in\">set<\/span> -euo pipefail\n\nrepo_root=$(git rev-parse --show-toplevel 2&gt;\/dev\/null || <span class=\"hljs-literal\">true<\/span>)\n<span class=\"hljs-keyword\">if<\/span> &#91;&#91; <span class=\"hljs-string\">\"<span class=\"hljs-variable\">${repo_root}<\/span>\"<\/span> == <span class=\"hljs-string\">\"<span class=\"hljs-variable\">${HOME}<\/span>\/upstream\"<\/span>* ]]; <span class=\"hljs-keyword\">then<\/span>\n  <span class=\"hljs-built_in\">echo<\/span> <span class=\"hljs-string\">\"skipping hooks in <span class=\"hljs-variable\">${repo_root}<\/span>\"<\/span>\n  <span class=\"hljs-built_in\">exit<\/span> 0\n<span class=\"hljs-keyword\">fi<\/span>\n\nhook=$(basename <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$0<\/span>\"<\/span>)\nreponame=$(git remote get-url origin 2&gt;\/dev\/null | gsed <span class=\"hljs-string\">'s|.*&#91;\/:]||; s|\\.git$||'<\/span> || basename <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$(git rev-parse --show-toplevel)<\/span>\"<\/span>)\noverride=<span class=\"hljs-string\">\"<span class=\"hljs-variable\">${HOME}<\/span>\/.githooks\/repos\/<span class=\"hljs-variable\">${reponame}<\/span>\/lefthook.yml\"<\/span>\nglobal=<span class=\"hljs-string\">\"<span class=\"hljs-variable\">${HOME}<\/span>\/.githooks\/lefthook.yml\"<\/span>\n\n<span class=\"hljs-keyword\">if<\/span> &#91;&#91; -f <span class=\"hljs-string\">\"<span class=\"hljs-variable\">${override}<\/span>\"<\/span> ]]; <span class=\"hljs-keyword\">then<\/span>\n  LEFTHOOK_CONFIG=<span class=\"hljs-string\">\"<span class=\"hljs-variable\">${override}<\/span>\"<\/span> lefthook run <span class=\"hljs-string\">\"<span class=\"hljs-variable\">${hook}<\/span>\"<\/span> --no-auto-install\n<span class=\"hljs-keyword\">elif<\/span> &#91;&#91; -f <span class=\"hljs-string\">\"<span class=\"hljs-variable\">${global}<\/span>\"<\/span> ]]; <span class=\"hljs-keyword\">then<\/span>\n  LEFTHOOK_CONFIG=<span class=\"hljs-string\">\"<span class=\"hljs-variable\">${global}<\/span>\"<\/span> lefthook run <span class=\"hljs-string\">\"<span class=\"hljs-variable\">${hook}<\/span>\"<\/span> --no-auto-install\n<span class=\"hljs-keyword\">fi<\/span>\n\n<span class=\"hljs-keyword\">for<\/span> precommit_cfg <span class=\"hljs-keyword\">in<\/span> .pre-commit-config.yaml .pre-commit-config.yml; <span class=\"hljs-keyword\">do<\/span>\n  <span class=\"hljs-keyword\">if<\/span> &#91;&#91; -f <span class=\"hljs-string\">\"<span class=\"hljs-variable\">${precommit_cfg}<\/span>\"<\/span> ]]; <span class=\"hljs-keyword\">then<\/span>\n    <span class=\"hljs-built_in\">echo<\/span> <span class=\"hljs-string\">\"\"<\/span>\n    <span class=\"hljs-built_in\">echo<\/span> <span class=\"hljs-string\">\"running hooks defined in <span class=\"hljs-variable\">${precommit_cfg}<\/span>\"<\/span>\n    pre-commit run --hook-stage <span class=\"hljs-string\">\"<span class=\"hljs-variable\">${hook}<\/span>\"<\/span> --config <span class=\"hljs-string\">\"<span class=\"hljs-variable\">${precommit_cfg}<\/span>\"<\/span>\n    <span class=\"hljs-built_in\">break<\/span>\n  <span class=\"hljs-keyword\">fi<\/span>\n<span class=\"hljs-keyword\">done<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Bash<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">bash<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Customize this for your own topology &#8211; I use <code>~\/upstream<\/code> for third party projects I want to be able to read the source of, but not run hooks in.  Individual repositories can override the lefthook config file to disable specific linters or add their own.  And the team-wide pre-commit config files still get run, even if they are sometimes duplicative.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That global lefthook.yml is straightforward, if somewhat verbose:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"YAML\" data-shcb-language-slug=\"yaml\"><span><code lang=\"yaml\" class=\"hljs language-yaml language-yaml\"><span class=\"hljs-meta\">---<\/span>\n<span class=\"hljs-attr\">output:<\/span>\n  <span class=\"hljs-bullet\">-<\/span> <span class=\"hljs-string\">meta<\/span>\n  <span class=\"hljs-bullet\">-<\/span> <span class=\"hljs-string\">success<\/span>\n  <span class=\"hljs-bullet\">-<\/span> <span class=\"hljs-string\">failure<\/span>\n  <span class=\"hljs-bullet\">-<\/span> <span class=\"hljs-string\">skips<\/span>\n  <span class=\"hljs-bullet\">-<\/span> <span class=\"hljs-string\">summary<\/span>\n\n<span class=\"hljs-attr\">pre-commit:<\/span>\n  <span class=\"hljs-attr\">commands:<\/span>\n    <span class=\"hljs-attr\">protect-main:<\/span>\n      <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">|\n        branch=$(git branch --show-current)\n        case \"$branch\" in\n          main|master|develop)\n            echo \"Direct commits to '$branch' are not allowed. Create a feature branch first.\"\n            exit 1\n            ;;\n        esac\n<\/span>\n    <span class=\"hljs-attr\">no-cwd-drift:<\/span>\n      <span class=\"hljs-attr\">skip:<\/span>\n        <span class=\"hljs-bullet\">-<\/span> <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">\"! { test -d .claude\/hooks || test -f go.work; }\"<\/span>\n      <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">|\n        repo_root=$(git rev-parse --show-toplevel)\n        cwd=$(pwd -P)\n        if &#91;&#91; \"${cwd}\" != \"${repo_root}\" ]]; then\n          echo \"error: hooks must run from repo root (${repo_root}), not ${cwd}\"\n          exit 1\n        fi\n<\/span>\n    <span class=\"hljs-attr\">whitespace:<\/span>\n      <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">git<\/span> <span class=\"hljs-string\">diff-index<\/span> <span class=\"hljs-string\">--check<\/span> <span class=\"hljs-string\">--cached<\/span> <span class=\"hljs-string\">HEAD<\/span> <span class=\"hljs-string\">--<\/span> <span class=\"hljs-string\">':!*.patch'<\/span>\n\n    <span class=\"hljs-attr\">no-conflict-markers:<\/span>\n      <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">|\n        files=$(git diff --cached --name-only)\n        if &#91; -n \"$files\" ]; then\n          if echo \"$files\" | xargs grep -lP '^(&lt;{7}|={7}|&gt;{7})' 2&gt;\/dev\/null; then\n            echo \"Conflict markers found in staged files. Resolve before committing.\"\n            exit 1\n          fi\n        fi\n<\/span>\n    <span class=\"hljs-attr\">markdown:<\/span>\n      <span class=\"hljs-attr\">glob:<\/span> <span class=\"hljs-string\">\"*.md\"<\/span>\n      <span class=\"hljs-attr\">exclude:<\/span>\n        <span class=\"hljs-bullet\">-<\/span> <span class=\"hljs-string\">\"**\/CLAUDE.md\"<\/span>\n        <span class=\"hljs-bullet\">-<\/span> <span class=\"hljs-string\">\"CLAUDE.md\"<\/span>\n        <span class=\"hljs-bullet\">-<\/span> <span class=\"hljs-string\">\"**\/AGENTS.md\"<\/span>\n        <span class=\"hljs-bullet\">-<\/span> <span class=\"hljs-string\">\"AGENTS.md\"<\/span>\n        <span class=\"hljs-bullet\">-<\/span> <span class=\"hljs-string\">\"ai\/**\"<\/span>\n      <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">markdownlint-cli2<\/span> <span class=\"hljs-string\">--config<\/span> <span class=\"hljs-string\">~\/.markdownlint.yaml<\/span> <span class=\"hljs-string\">{staged_files}<\/span>\n\n    <span class=\"hljs-attr\">shellcheck:<\/span>\n      <span class=\"hljs-attr\">glob:<\/span> <span class=\"hljs-string\">\"*.sh\"<\/span>\n      <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">shellcheck<\/span> <span class=\"hljs-string\">{staged_files}<\/span>\n\n    <span class=\"hljs-attr\">python:<\/span>\n      <span class=\"hljs-attr\">glob:<\/span> <span class=\"hljs-string\">\"*.{py,py3}\"<\/span>\n      <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">ruff<\/span> <span class=\"hljs-string\">check<\/span> <span class=\"hljs-string\">{staged_files}<\/span>\n\n    <span class=\"hljs-attr\">javascript:<\/span>\n      <span class=\"hljs-attr\">glob:<\/span> <span class=\"hljs-string\">\"*.{js,jsx,ts,tsx,mjs,cjs}\"<\/span>\n      <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">eslint<\/span> <span class=\"hljs-string\">{staged_files}<\/span>\n\n    <span class=\"hljs-attr\">ruby:<\/span>\n      <span class=\"hljs-attr\">glob:<\/span> <span class=\"hljs-string\">\"*.rb\"<\/span>\n      <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">rubocop<\/span> <span class=\"hljs-string\">{staged_files}<\/span>\n\n    <span class=\"hljs-attr\">golang:<\/span>\n      <span class=\"hljs-attr\">glob:<\/span> <span class=\"hljs-string\">\"{*.go,go.mod,go.sum}\"<\/span>\n      <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">$HOME\/.githooks\/linters\/golang<\/span>\n\n    <span class=\"hljs-attr\">terraform:<\/span>\n      <span class=\"hljs-attr\">glob:<\/span> <span class=\"hljs-string\">\"*.tf\"<\/span>\n      <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">$HOME\/.githooks\/linters\/terraform<\/span>\n\n    <span class=\"hljs-attr\">yaml:<\/span>\n      <span class=\"hljs-attr\">glob:<\/span> <span class=\"hljs-string\">\"*.{yml,yaml}\"<\/span>\n      <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">$HOME\/.githooks\/linters\/yaml<\/span>\n\n    <span class=\"hljs-attr\">php:<\/span>\n      <span class=\"hljs-attr\">glob:<\/span> <span class=\"hljs-string\">\"*.php\"<\/span>\n      <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">$HOME\/.githooks\/linters\/php<\/span>\n\n    <span class=\"hljs-attr\">gitleaks:<\/span>\n      <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">$HOME\/.githooks\/linters\/gitleaks<\/span>\n\n    <span class=\"hljs-attr\">buf:<\/span>\n      <span class=\"hljs-attr\">glob:<\/span> <span class=\"hljs-string\">\"*.proto\"<\/span>\n      <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">$HOME\/.githooks\/linters\/buf<\/span>\n\n    <span class=\"hljs-attr\">actionlint:<\/span>\n      <span class=\"hljs-attr\">glob:<\/span> <span class=\"hljs-string\">\".github\/workflows\/*.{yml,yaml}\"<\/span>\n      <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">$HOME\/.githooks\/linters\/actionlint<\/span>\n\n    <span class=\"hljs-attr\">hadolint:<\/span>\n      <span class=\"hljs-attr\">glob:<\/span> <span class=\"hljs-string\">\"Dockerfile*\"<\/span>\n      <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">$HOME\/.githooks\/linters\/hadolint<\/span>\n\n    <span class=\"hljs-attr\">helm:<\/span>\n      <span class=\"hljs-attr\">glob:<\/span> <span class=\"hljs-string\">\"Chart.yaml\"<\/span>\n      <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">$HOME\/.githooks\/linters\/helm<\/span>\n\n    <span class=\"hljs-attr\">jsonlint:<\/span>\n      <span class=\"hljs-attr\">glob:<\/span> <span class=\"hljs-string\">\"*.json\"<\/span>\n      <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">$HOME\/.githooks\/linters\/jsonlint<\/span>\n\n    <span class=\"hljs-attr\">kubeconform:<\/span>\n      <span class=\"hljs-attr\">glob:<\/span> <span class=\"hljs-string\">\"*.{yml,yaml}\"<\/span>\n      <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">$HOME\/.githooks\/linters\/kubeconform<\/span>\n\n    <span class=\"hljs-attr\">stylelint:<\/span>\n      <span class=\"hljs-attr\">glob:<\/span> <span class=\"hljs-string\">\"*.{css,scss,sass,less}\"<\/span>\n      <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">$HOME\/.githooks\/linters\/stylelint<\/span>\n\n    <span class=\"hljs-attr\">taplo:<\/span>\n      <span class=\"hljs-attr\">glob:<\/span> <span class=\"hljs-string\">\"*.toml\"<\/span>\n      <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">$HOME\/.githooks\/linters\/taplo<\/span>\n\n    <span class=\"hljs-attr\">prettier:<\/span>\n      <span class=\"hljs-attr\">glob:<\/span> <span class=\"hljs-string\">\"*.{md,json,js,jsx,ts,tsx,css,scss,yaml,yml,html}\"<\/span>\n      <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">$HOME\/.githooks\/linters\/prettier<\/span> <span class=\"hljs-string\">{staged_files}<\/span>\n\n    <span class=\"hljs-attr\">prose:<\/span>\n      <span class=\"hljs-attr\">glob:<\/span> <span class=\"hljs-string\">\"*.md\"<\/span>\n      <span class=\"hljs-attr\">skip:<\/span>\n        <span class=\"hljs-bullet\">-<\/span> <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">test<\/span> <span class=\"hljs-string\">!<\/span> <span class=\"hljs-string\">-f<\/span> <span class=\"hljs-string\">.vale.ini<\/span>\n      <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">vale<\/span> <span class=\"hljs-string\">{staged_files}<\/span>\n\n<span class=\"hljs-attr\">pre-push:<\/span>\n  <span class=\"hljs-attr\">commands:<\/span>\n    <span class=\"hljs-attr\">test:<\/span>\n      <span class=\"hljs-comment\"># Skip only when the repo has no Go module anywhere (not just at the root).<\/span>\n      <span class=\"hljs-attr\">skip:<\/span>\n        <span class=\"hljs-bullet\">-<\/span> <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">\"! git ls-files '*go.mod' | grep -q .\"<\/span>\n      <span class=\"hljs-comment\"># Run tests per module so repos whose go.mod lives in subdirectories are covered.<\/span>\n      <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">|\n        rc=0\n        for mod in $(git ls-files '*go.mod'); do\n          ( cd \"$(dirname \"$mod\")\" &amp;&amp; go test -race .\/... ) || rc=1\n        done\n        exit $rc\n<\/span>\n    <span class=\"hljs-attr\">gocognit:<\/span>\n      <span class=\"hljs-attr\">skip:<\/span>\n        <span class=\"hljs-bullet\">-<\/span> <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">\"! git ls-files '*go.mod' | grep -q .\"<\/span>\n      <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">$HOME\/.githooks\/linters\/gocognit<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">YAML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">yaml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">That&#8217;s the selling point of lefthook &#8211; it handles the file name patterns for us, so our hooks can just execute on the file names they&#8217;re given.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">One trivial caveat:  per-repo overrides are only achievable by using the full path to the upstream config file, variable and tilde expansion don&#8217;t work here:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"YAML\" data-shcb-language-slug=\"yaml\"><span><code lang=\"yaml\" class=\"hljs language-yaml language-yaml\"><span class=\"hljs-string\">$<\/span> <span class=\"hljs-string\">cat<\/span> <span class=\"hljs-string\">${HOME}\/.githooks\/repos\/${reponame}\/lefthook.yml<\/span>\n<span class=\"hljs-attr\">extends:<\/span>\n  <span class=\"hljs-bullet\">-<\/span> <span class=\"hljs-string\">\/home\/&lt;user&gt;\/.githooks\/lefthook.yml<\/span>\n\n<span class=\"hljs-attr\">pre-commit:<\/span>\n  <span class=\"hljs-attr\">commands:<\/span>\n    <span class=\"hljs-attr\">prettier:<\/span>\n      <span class=\"hljs-attr\">skip:<\/span> <span class=\"hljs-literal\">true<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">YAML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">yaml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That&#8217;s it.  Global hooks for whatever linting and testing one could want to invoke.  No per-repo configuration, no git templates, no pull requests required.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Every once in a while, you&#8217;ll encounter a repository that ships its own hooks and think &#8220;I should do that for all my repos too!&#8221;, except you never quite get around to it, because there are dozens of repositories in play, some of them are low-traffic while others have esoteric linter configurations. But what about [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_genesis_hide_title":false,"_genesis_hide_breadcrumbs":false,"_genesis_hide_singular_image":false,"_genesis_hide_footer_widgets":false,"_genesis_custom_body_class":"","_genesis_custom_post_class":"","_genesis_layout":"","footnotes":""},"categories":[1],"tags":[],"class_list":["post-45","post","type-post","status-publish","format-standard","category-tech","entry"],"featured_image_src":null,"featured_image_src_square":null,"author_info":{"display_name":"jshort","author_link":"https:\/\/jcshort.net\/?author=2"},"_links":{"self":[{"href":"https:\/\/jcshort.net\/index.php?rest_route=\/wp\/v2\/posts\/45","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jcshort.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jcshort.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jcshort.net\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/jcshort.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=45"}],"version-history":[{"count":2,"href":"https:\/\/jcshort.net\/index.php?rest_route=\/wp\/v2\/posts\/45\/revisions"}],"predecessor-version":[{"id":49,"href":"https:\/\/jcshort.net\/index.php?rest_route=\/wp\/v2\/posts\/45\/revisions\/49"}],"wp:attachment":[{"href":"https:\/\/jcshort.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=45"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jcshort.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=45"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jcshort.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=45"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}