Leveraging Git Hooks to Fix Markdown Issues Automatically
Recently, Jacob Tomlinson wrote an excellent post about a frustrating issue with Markdown titles: sometimes they don't render properly, even when they look fine in an editor.
The culprit? Non-breaking spaces (\xa0
) sneaking in after the #
characters instead of normal spaces (\x20
). This often happens on macOS if you accidentally press ⌥ + SPACE instead of just SPACE.
Jacob's post explains the problem in detail, but I wanted to take it a step further: How can we automatically prevent this from ever happening?
Automatically fixing non-breaking spaces with git hooks
If you edit markdown locally before committing to git, a pre-commit hook is an easy way to catch and fix this issue before it even reaches your repository.
A pre-commit hook is a small script that runs automatically before you commit files.
We can use it to scan all .md
files for non-breaking spaces and replace them with normal spaces.
Pre-commit hook to fix markdown headings
Save the following script as .git/hooks/pre-commit
in your repository:
#!/bin/bash
# Find and replace non-breaking spaces in all markdown files
find . -name "*.md" -type f -print0 | while IFS= read -r -d '' file; do
if grep -q $'\xa0' "$file"; then
echo "Fixing non-breaking spaces in: $file"
sed -i '' 's/\xa0/ /g' "$file"
fi
done
exit 0
Make it executable:
chmod +x .git/hooks/pre-commit
Now, every time you commit, this script will ensure that all markdown files in that repository have the correct spaces in headings.
Setting up a global git hook
If you want to take this a step further and avoid setting it up for each individual repo, you can configure a global git hook.
Create a directory for global hooks:
mkdir -p ~/.git-hooks
Move the script local pre-commit
there:
mv /my-repo/.git/hooks/pre-commit ~/.git-hooks/pre-commit
Make it executable:
chmod +x ~/.git-hooks/pre-commit
Configure git to use the global hook directory:
git config --global core.hooksPath ~/.git-hooks
Now, every Git repository you work on will automatically apply this fix before committing - no more manual setup per project.
Linting markdown with markdownlint
While the git hook above solves this specific issue, it's also worth using a linter like markdownlint to catch other formatting problems.
This does require npm
to run, but if you frequently write markdown or need to maintain consistency across your documents, it's well worth it.
Installing markdownlint
Assuming you have npm
installed already, install the package globally with:
npm install -g markdownlint-cli
Then, to manually check a markdown file:
markdownlint README.md
If you don't set up your own ruleset for the linter, then it will use the default recommended values
To automatically fix issues:
markdownlint --fix README.md
Using markdownlint in a pre-commit hook
You can modify the global git hook to also run markdownlint
before every commit:
#!/bin/bash
# Fix non-breaking spaces
find . -name "*.md" -type f -print0 | while IFS= read -r -d '' file; do
if grep -q $'\xa0' "$file"; then
echo "Fixing non-breaking spaces in: $file"
sed -i '' 's/\xa0/ /g' "$file"
fi
done
# Run markdownlint
if command -v markdownlint &> /dev/null; then
echo "Running markdownlint..."
markdownlint --fix .
fi
exit 0
With this setup, your markdown files will automatically be cleaned up and formatted before every commit.
Final Thoughts
Jacob's article highlights an issue that can be frustrating, especially when you're dealing with multiple markdown parsers.
But with git hooks and markdownlint
, you can automate the fix and never worry about broken markdown titles again.
If you work with markdown often, setting up these tools once will save you countless hours of debugging or formatting.
If you found this article helpful, you can keep the ideas flowing by supporting me. Buy me a coffee or check out my apps to help me create more content like this!
Coffee Check out my apps