Last active
August 7, 2025 13:24
-
-
Save heftig/a53fd4a72382bce2502c353d4c42b397 to your computer and use it in GitHub Desktop.
"lint-wrap" helper for Git pre-commit scripts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Usage: lint-wrap <command> [<arguments>...] | |
# Example: lint-wrap cargo fmt | |
# | |
# The provided command is run with the working tree cleaned of unstaged changes | |
# and untracked files. | |
# | |
# If the command changes any tracked files, the changes are staged. | |
# | |
# This script is intended to wrap a linter or code formatter to be run on | |
# pre-commit. When committing part of the changes in the tree, this ensures the | |
# changes that actually get committed are linted. | |
# | |
# SPDX-License-Identifier: 0BSD | |
# Copyright (c) 2025 Jan Alexander Steffens (heftig) <[email protected]> | |
# | |
# Permission to use, copy, modify, and/or distribute this software for any | |
# purpose with or without fee is hereby granted. | |
# | |
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH | |
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | |
# AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, | |
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM | |
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR | |
# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | |
# PERFORMANCE OF THIS SOFTWARE. | |
# Enable exit-on-error and disable globbing | |
set -ef | |
# Make sure we're in the working tree root | |
cd -- "$(git rev-parse --show-toplevel)" | |
msg() { | |
local attr="$1"; shift | |
echo -e "\e[${attr}m$*\e[0m" >&2 | |
} | |
# Runs on any exit from this script | |
restore() { | |
if (( ${#untracked_files[@]} > 0 )); then | |
msg 90 "Restoring untracked files from $untracked" | |
git read-tree --reset -u $untracked | |
git rm -q --cached -- "${untracked_files[@]}" | |
fi | |
if [[ -n $unstaged ]]; then | |
msg 90 "Restoring unstaged files from $unstaged" | |
git read-tree --reset -u $unstaged | |
fi | |
if [[ -n $staged ]]; then | |
msg 90 "Restoring staged files from $staged" | |
git read-tree --reset $staged | |
fi | |
} | |
untracked_files=() | |
untracked= | |
unstaged= | |
staged= | |
trap restore EXIT | |
# Save staged and unstaged changes | |
staged=$(git write-tree) | |
msg 90 "Saved staged files to $staged" | |
git add --update | |
unstaged=$(git write-tree) | |
msg 90 "Saved unstaged files to $unstaged" | |
# Save untracked files, if any | |
mapfile -t -d '' untracked_files \ | |
< <(git ls-files -z --others --exclude-standard) | |
if (( ${#untracked_files[@]} > 0 )); then | |
git add -- "${untracked_files[@]}" | |
untracked=$(git write-tree) | |
msg 90 "Saved untracked files to $untracked" | |
fi | |
# Remove unstaged changes and untracked files | |
git read-tree --reset -u $staged | |
# Our tree is clean, process it now | |
msg 1 "Running $*" | |
"$@" | |
# Success! Stage any new changes | |
git add --update | |
staged=$(git write-tree) | |
msg 90 "Saved staged files to $staged" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment