如何通过Git预提交钩子调用自定义.exe格式化待提交变更文件?
Absolutely doable! Git pre-commit hooks were made exactly for this kind of pre-submission automation. Let’s walk through two practical solutions that fit your preferences—starting with a simple batch script (no fancy coding required), then a more flexible C# console app. I’ll also cover all the setup steps you need to get this working.
1. Quick Primer on Git Pre-Commit Hooks
Git hooks are small scripts that run automatically at specific points in the Git workflow. The pre-commit hook runs right before a commit is finalized—if it returns an exit code of 0, the commit proceeds; if it returns any non-zero value, the commit is blocked.
By default, your Git repo has a sample hook file at .git/hooks/pre-commit.sample. To use your own hook, just copy this file, rename it to pre-commit (no file extension), and replace its contents with your automation logic.
2. Solution 1: Batch Script (.bat) Approach
This is the fastest way to get up and running, perfect if you want minimal setup.
Step 1: Create the Formatting Script
Make a new file named format-files.bat in your repo’s root directory, and paste this code (adjust paths to match your setup):
@echo off setlocal enabledelayedexpansion :: Replace this with the full path to your formatting .exe set FORMATTER_EXE="C:\Tools\YourFormatter.exe" :: Get all staged files (skip deleted files) for /f "delims=" %%f in ('git diff --cached --name-only --diff-filter=ACM') do ( echo Formatting: %%f :: Run your formatter on the file %FORMATTER_EXE% "%%f" :: Re-stage the file since formatting might have modified it git add "%%f" ) :: Return 0 to allow the commit to proceed exit /b 0
Step 2: Wire Up the Pre-Commit Hook
- Go to your repo’s
.git/hooksfolder. - Copy
pre-commit.sampleand rename the copy topre-commit(remove the.sampleextension). - Open the new
pre-commitfile and replace all its contents with this:
#!/bin/sh # Call our batch script to format staged files ./format-files.bat
- Ensure the hook has execute permissions. In Git Bash, run:
git update-index --chmod=+x .git/hooks/pre-commit
3. Solution 2: C# Console App Approach
If you need more control (like filtering specific file types, adding error handling, or complex logic), a C# console app is a great choice.
Step 1: Build the C# Formatter Wrapper
Create a new C# Console App project, and replace the Program.cs code with this (adjust paths and logic as needed):
using System; using System.Diagnostics; using System.IO; namespace GitPreCommitFormatter { class Program { static void Main(string[] args) { // Path to your custom formatting .exe var formatterPath = @"C:\Tools\YourFormatter.exe"; if (!File.Exists(formatterPath)) { Console.WriteLine($"Error: Couldn't find formatter at {formatterPath}"); Environment.Exit(1); // Block commit on error } // Get list of staged files from Git var gitDiffProcess = new ProcessStartInfo { FileName = "git", Arguments = "diff --cached --name-only --diff-filter=ACM", RedirectStandardOutput = true, UseShellExecute = false, CreateNoWindow = true }; using (var process = Process.Start(gitDiffProcess)) { process.WaitForExit(); if (process.ExitCode != 0) { Console.WriteLine("Error: Failed to fetch staged files from Git"); Environment.Exit(1); } var stagedFiles = process.StandardOutput.ReadToEnd() .Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); foreach (var file in stagedFiles) { if (!File.Exists(file)) { Console.WriteLine($"Warning: File {file} doesn't exist—skipping"); continue; } Console.WriteLine($"Formatting {file}..."); // Run your formatter on the file var formatterProcess = Process.Start(formatterPath, $"\"{file}\""); formatterProcess.WaitForExit(); if (formatterProcess.ExitCode != 0) { Console.WriteLine($"Error: Failed to format {file}"); Environment.Exit(1); // Block commit if formatting fails } // Re-stage the modified file var gitAddProcess = Process.Start("git", $"add \"{file}\""); gitAddProcess.WaitForExit(); if (gitAddProcess.ExitCode != 0) { Console.WriteLine($"Error: Failed to re-stage {file}"); Environment.Exit(1); } } } // All good—allow commit Environment.Exit(0); } } }
Compile the project to get an executable (e.g., GitPreCommitFormatter.exe).
Step 2: Set Up the Pre-Commit Hook
Follow the same hook setup steps as the batch solution, but replace the pre-commit contents with a call to your C# exe:
#!/bin/sh # Call our C# formatter wrapper "C:\Path\To\GitPreCommitFormatter.exe"
Or if you prefer a batch-style hook:
@echo off call "C:\Path\To\GitPreCommitFormatter.exe" exit /b %errorlevel%
4. Key Tips to Avoid Headaches
- Test First: Modify a file, stage it with
git add, then rungit committo verify the hook works. If formatting fails, the commit should be blocked with an error message. - File Filtering: If you only want to format specific file types (e.g.,
.cs,.json), add a check in your script/C# code. For example, in batch:if "%%~xf"==".cs", or in C#:if (Path.GetExtension(file).Equals(".cs", StringComparison.OrdinalIgnoreCase)). - Formatter Behavior: Ensure your custom .exe overwrites the original file (not creates a new one)—this way,
git addpicks up the formatted changes correctly. - Permissions: On Windows, make sure the
pre-commitfile has execute permissions (use thegit update-index --chmod=+xcommand if needed).
内容的提问来源于stack exchange,提问作者johnsontroye

