如何精确匹配含特殊字符的Git提交信息并获取提交哈希
Solution: Exact Commit Message Match with Special Characters Handling
To write a Bash function get_commits_by_message() that returns commit hashes where the entire commit message exactly matches your input (even when it contains special characters, spaces, or newlines), here's a robust implementation:
get_commits_by_message() { local target_message="$1" # Use git log to output each commit's hash and full message, separated by a unique delimiter git log --all --format="%H%n%B%n===COMMIT_BOUNDARY===" | awk -v target="$target_message" ' BEGIN { current_hash = "" current_msg = "" in_msg = 0 } $0 == "===COMMIT_BOUNDARY===" { # Compare accumulated message to target (exact match) if (current_msg == target) { print current_hash } # Reset for next commit current_hash = "" current_msg = "" in_msg = 0 next } !in_msg { current_hash = $0 in_msg = 1 next } in_msg { # Append lines to message, preserving newlines current_msg = current_msg (current_msg != "" ? "\n" : "") $0 } ' }
How It Works
Git Log Formatting: We use
git log --all --format="%H%n%B%n===COMMIT_BOUNDARY==="to output:%H: The full commit hash%B: The complete commit message (including all lines, not just the subject)- A unique delimiter (
===COMMIT_BOUNDARY===) to separate each commit's data. Pick something that won't appear in any of your commit messages.
Awk Processing: The awk script parses the git log output:
- Tracks the current commit hash and accumulates every line of the message.
- When it hits the delimiter, it checks if the accumulated message exactly matches your target input.
- If there's a match, it prints the commit hash.
Alternative: Simpler (But Slower for Large Repos)
If you prefer a more straightforward approach (easier to debug, but less efficient for repos with thousands of commits), you can loop through each commit and compare messages directly:
get_commits_by_message() { local target_message="$1" git rev-list --all | while read -r commit_hash; do # Extract the full commit message (skip the commit header) local commit_msg=$(git cat-file commit "$commit_hash" | sed '1,/^$/d') # Exact string comparison (handles newlines and special characters) if [ "$commit_msg" = "$target_message" ]; then echo "$commit_hash" fi done }
Key Notes
- Multi-Line Messages: Both implementations correctly handle multi-line commit messages, as they preserve and compare all lines of the message.
- Special Characters: By using exact string comparison (instead of regex), we avoid issues with special characters like
*,?,[], or$that would break regex-based searches. - Trailing Newlines: Git typically appends a trailing newline to commit messages. If your target message doesn't include this newline, the comparison may fail. To fix this, you can add a trailing newline to
target_message(e.g.,target_message="$1"$'\n'). - Scope: Both scripts use
--allto search all branches. If you want to limit to a specific branch, replace--allwith the branch name (e.g.,main).
内容的提问来源于stack exchange,提问作者Marvin Irwin
相关产品推荐
相关产品推荐

