You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何精确匹配含特殊字符的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

  1. 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.
  2. 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 --all to search all branches. If you want to limit to a specific branch, replace --all with the branch name (e.g., main).

内容的提问来源于stack exchange,提问作者Marvin Irwin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 12:47:45