diff --git a/Dist/git_hooks/commit-msg b/Dist/git_hooks/commit-msg
new file mode 100755
index 0000000000..6e96f0fc1e
--- /dev/null
+++ b/Dist/git_hooks/commit-msg
@@ -0,0 +1,14 @@
+#!/usr/bin/env -S dotnet pwsh
+# placed here by BizHawk build scripts and may be updated automatically
+$msg = Get-Content $args[0] -TotalCount 1 # this commit hook is always passed the commit message scratch file's path, so read the first line of that
+if ($msg -Match "^fix(?:ed|es)? #\d+$") {
+	echo "An issue reference alone is not a suitable commit message. Vetoed."
+	exit 1
+}
+if ($msg.Length -lt 20) { # arbitrary
+	if ($msg.Length -lt 8) { # semi-arbitrary; I figured "Fix typo" would be the shortest reasonable message --yoshi
+		echo "Your commit message is too short. Vetoed."
+		exit 1
+	}
+	echo "Your commit message is a bit short. Do you have more to add? (If you included a longer description already, ignore this.)"
+}
diff --git a/Dist/install_git_hooks.ps1 b/Dist/install_git_hooks.ps1
new file mode 100644
index 0000000000..2d2d4cd870
--- /dev/null
+++ b/Dist/install_git_hooks.ps1
@@ -0,0 +1,19 @@
+$targetDir = "$PSScriptRoot/../.git/hooks"
+if (Test-Path $targetDir -PathType Container) { # is Git repo
+	$magicHeader = '# placed here by BizHawk build scripts and may be updated automatically'
+	$PSCommandFilename = Split-Path $PSCommandPath -Leaf
+	foreach ($f in Get-ChildItem "$PSScriptRoot/git_hooks") {
+		$target = Join-Path $targetDir $f.Name
+		if ($(Get-FileHash $target).Hash -ne $(Get-FileHash $f.FullName).Hash) {
+			$head = Get-Content $target -TotalCount 3
+			if ($magicHeader -in $head) {
+				echo "[$PSCommandFilename] updating existing Git hook $($f.Name)"
+				Copy-Item $f $target
+			} else {
+				echo "[$PSCommandFilename] found existing Git hook $($f.Name), please resolve conflict manually"
+				# should probably make the scripts extensible then...
+				exit 1
+			}
+		}
+	}
+}
diff --git a/src/BizHawk.Common/BizHawk.Common.csproj b/src/BizHawk.Common/BizHawk.Common.csproj
index 24c4133698..45ee07b38e 100644
--- a/src/BizHawk.Common/BizHawk.Common.csproj
+++ b/src/BizHawk.Common/BizHawk.Common.csproj
@@ -16,4 +16,7 @@
 	<ItemGroup>
 		<Analyzer Include="$(MSBuildProjectDirectory)/../../References/BizHawk.SrcGen.VersionInfo.dll" />
 	</ItemGroup>
+	<Target Name="InstallGitHooks" BeforeTargets="PreBuildEvent">
+		<Exec Command="dotnet pwsh $(MSBuildProjectDirectory)/../../Dist/install_git_hooks.ps1" />
+	</Target>
 </Project>