Created
August 25, 2025 12:47
-
-
Save reduardo7/87929d2b08130a0bc07dc47895ed1449 to your computer and use it in GitHub Desktop.
GIT Repository History scanner
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 | |
| # Analyzes git commit history to find ticket-related commits | |
| # Usage: ./repository-history.sh [-h COMMIT_HASH] [-t TICKET] [-a AUTHOR] [-d DAYS] | |
| # - Without arguments: Shows ticket commits from current branch (last 30 days) | |
| # - -h COMMIT_HASH: Shows ticket commits up to that hash in current branch (within specified days) | |
| # - -t TICKET: Filters results to show only commits for specific ticket (e.g., OV-12345) | |
| # - -a AUTHOR: Filters results by author name/email (case-insensitive partial match) | |
| # - -d DAYS: Number of days to look back (default: 30) | |
| # - All flags can be combined: -h HASH -t TICKET -a AUTHOR -d DAYS | |
| # Note: COMMIT_HASH must exist in current branch | |
| # Tickets follow the configured pattern (configurable in CONFIGURATION SECTION) | |
| set -e | |
| # ============================================================================= | |
| # CONFIGURATION SECTION | |
| # ============================================================================= | |
| # Customize these variables for different projects or ticket systems | |
| # Ticket pattern configuration | |
| TICKET_PREFIX="AB" # Ticket prefix (e.g., AB, JIRA, PROJ) | |
| TICKET_PATTERN="$TICKET_PREFIX-[0-9]+" # Full regex pattern for tickets | |
| TICKET_EXAMPLE="$TICKET_PREFIX-12345" # Example ticket for help messages | |
| # Default values | |
| DEFAULT_DAYS=30 # Default number of days to look back | |
| # Display configuration | |
| DATE_FORMAT="%Y-%m-%d %H:%M:%S" # Format for commit dates | |
| SEPARATOR_LINE="=================================================================" | |
| # ============================================================================= | |
| # Function to display ticket commits from git log output | |
| display_ticket_commits() { | |
| local ticket_filter="$1" | |
| local author_filter="$2" | |
| local filter_pipeline="grep -E '$TICKET_PATTERN'" | |
| # Add ticket filter if specified | |
| if [ -n "$ticket_filter" ]; then | |
| filter_pipeline="$filter_pipeline | grep -i '$ticket_filter'" | |
| fi | |
| # Add author filter if specified | |
| if [ -n "$author_filter" ]; then | |
| filter_pipeline="$filter_pipeline | grep -i '$author_filter'" | |
| fi | |
| eval "$filter_pipeline" | \ | |
| while IFS='|' read -r hash author date message; do | |
| # Extract ticket numbers from the commit message | |
| tickets=$(echo "$message" | grep -oE "$TICKET_PATTERN" | sort -u | tr '\n' ', ' | sed 's/,$//') | |
| # Clean commit message by removing ticket prefix if it starts the message | |
| # Handles patterns like: "OV-1234 message", "OV-1234 - message", "OV-1234: message", etc. | |
| clean_message="$message" | |
| if [[ "$message" =~ ^$TICKET_PREFIX-[0-9]+[[:space:]]*[-:]*[[:space:]]* ]]; then | |
| clean_message=$(echo "$message" | sed -E "s/^$TICKET_PREFIX-[0-9]+[[:space:]]*[-:]*[[:space:]]*//" | sed 's/^[[:space:]]*//') | |
| fi | |
| echo "Commit: $hash" | |
| echo "Author: $author" | |
| echo "Date: $date" | |
| echo "Ticket(s): $tickets" | |
| echo "Message: $clean_message" | |
| echo "---" | |
| done | |
| } | |
| # Function to show summary statistics | |
| show_summary() { | |
| local context_desc="$1" | |
| local ticket_filter="$2" | |
| local author_filter="$3" | |
| shift 3 | |
| local git_log_args=("$@") | |
| echo | |
| echo "Analysis complete!" | |
| echo "Summary:" | |
| echo "========" | |
| total_commits=$(git log "${git_log_args[@]}" --oneline | wc -l | tr -d ' ') | |
| # Build filter pipeline for counting | |
| local filter_pipeline="git log \"${git_log_args[@]}\" --pretty=format:\"%h|%an|%ad|%s\" --date=format:\"$DATE_FORMAT\" | grep -E '$TICKET_PATTERN'" | |
| if [ -n "$ticket_filter" ]; then | |
| filter_pipeline="$filter_pipeline | grep -i '$ticket_filter'" | |
| fi | |
| if [ -n "$author_filter" ]; then | |
| filter_pipeline="$filter_pipeline | grep -i '$author_filter'" | |
| fi | |
| ticket_commits=$(eval "$filter_pipeline" | wc -l | tr -d ' ') | |
| echo "Total commits $context_desc: $total_commits" | |
| # Build description of filters | |
| local filter_desc="" | |
| if [ -n "$ticket_filter" ] && [ -n "$author_filter" ]; then | |
| filter_desc="with ticket $ticket_filter and author matching '$author_filter'" | |
| elif [ -n "$ticket_filter" ]; then | |
| filter_desc="with ticket $ticket_filter" | |
| elif [ -n "$author_filter" ]; then | |
| filter_desc="by author matching '$author_filter'" | |
| else | |
| filter_desc="with ticket references" | |
| fi | |
| echo "Commits $filter_desc: $ticket_commits" | |
| # List unique tickets found | |
| echo | |
| echo "Unique tickets found:" | |
| eval "$filter_pipeline" | while IFS='|' read -r hash author date message; do | |
| echo "$message" | grep -oE "$TICKET_PATTERN" | |
| done | sort -u | while read ticket; do | |
| echo " - $ticket" | |
| done | |
| } | |
| # Function to analyze commits with given git log arguments | |
| analyze_commits() { | |
| local context_desc="$1" | |
| local ticket_filter="$2" | |
| local author_filter="$3" | |
| shift 3 | |
| local git_log_args=("$@") | |
| git log "${git_log_args[@]}" --pretty=format:"%h|%an|%ad|%s" --date=format:"$DATE_FORMAT" | display_ticket_commits "$ticket_filter" "$author_filter" | |
| show_summary "$context_desc" "$ticket_filter" "$author_filter" "${git_log_args[@]}" | |
| } | |
| # Parse arguments using flags | |
| COMMIT_HASH="" | |
| TICKET_FILTER="" | |
| AUTHOR_FILTER="" | |
| DAYS="$DEFAULT_DAYS" | |
| while [[ $# -gt 0 ]]; do | |
| case $1 in | |
| -h|--hash) | |
| COMMIT_HASH="$2" | |
| shift 2 | |
| ;; | |
| -t|--ticket) | |
| TICKET_FILTER="$2" | |
| shift 2 | |
| ;; | |
| -a|--author) | |
| AUTHOR_FILTER="$2" | |
| shift 2 | |
| ;; | |
| -d|--days) | |
| DAYS="$2" | |
| # Validate that DAYS is a positive integer | |
| if ! [[ "$DAYS" =~ ^[0-9]+$ ]] || [ "$DAYS" -eq 0 ]; then | |
| echo "Error: Days must be a positive integer" | |
| exit 1 | |
| fi | |
| shift 2 | |
| ;; | |
| --help) | |
| echo "Usage: $0 [-h COMMIT_HASH] [-t TICKET] [-a AUTHOR] [-d DAYS]" | |
| echo " -h, --hash COMMIT_HASH Analyze commits up to specified hash" | |
| echo " -t, --ticket TICKET Filter by specific ticket (e.g., $TICKET_EXAMPLE)" | |
| echo " -a, --author AUTHOR Filter by author name/email (case-insensitive)" | |
| echo " -d, --days DAYS Number of days to look back (default: $DEFAULT_DAYS)" | |
| echo " --help Show this help message" | |
| echo "" | |
| echo "Examples:" | |
| echo " $0 # Show all tickets from current branch (last $DEFAULT_DAYS days)" | |
| echo " $0 -d 7 # Show tickets from last 7 days" | |
| echo " $0 -h 8b8e791b -d 14 # Show tickets up to commit within last 14 days" | |
| echo " $0 -t $TICKET_EXAMPLE # Show only commits for ticket $TICKET_EXAMPLE" | |
| echo " $0 -a john -d 60 # Show commits by 'john' from last 60 days" | |
| echo " $0 -h 8b8e791b -t $TICKET_EXAMPLE -a john -d 7 # Combine all filters" | |
| exit 0 | |
| ;; | |
| *) | |
| echo "Unknown option: $1" | |
| echo "Use --help for usage information" | |
| exit 1 | |
| ;; | |
| esac | |
| done | |
| # Handle commit hash validation and analysis | |
| if [ -n "$COMMIT_HASH" ]; then | |
| CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) | |
| # Validate if the commit hash exists in current branch | |
| if ! git merge-base --is-ancestor "$COMMIT_HASH" HEAD 2>/dev/null && [ "$COMMIT_HASH" != "$(git rev-parse HEAD 2>/dev/null)" ]; then | |
| # Commit hash is not in current branch or doesn't exist - return empty | |
| exit 0 | |
| fi | |
| echo "Analyzing commits reachable from: $COMMIT_HASH (last $DAYS days only)" | |
| if [ -n "$TICKET_FILTER" ]; then | |
| echo "Filtering by ticket: $TICKET_FILTER" | |
| fi | |
| if [ -n "$AUTHOR_FILTER" ]; then | |
| echo "Filtering by author: $AUTHOR_FILTER" | |
| fi | |
| echo "Time range: last $DAYS days" | |
| echo "Looking for commits containing ticket references ($TICKET_PREFIX-XXXXX)" | |
| echo "$SEPARATOR_LINE" | |
| echo | |
| analyze_commits "reachable from $COMMIT_HASH (last $DAYS days)" "$TICKET_FILTER" "$AUTHOR_FILTER" "$COMMIT_HASH" --since="$DAYS days ago" | |
| else | |
| # Default behavior - last N days from current branch | |
| CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) | |
| echo "Analyzing commits from branch: $CURRENT_BRANCH" | |
| if [ -n "$TICKET_FILTER" ]; then | |
| echo "Filtering by ticket: $TICKET_FILTER" | |
| fi | |
| if [ -n "$AUTHOR_FILTER" ]; then | |
| echo "Filtering by author: $AUTHOR_FILTER" | |
| fi | |
| echo "Time range: last $DAYS days" | |
| echo "Looking for commits from the last $DAYS days containing ticket references ($TICKET_PREFIX-XXXXX)" | |
| echo "$SEPARATOR_LINE" | |
| echo | |
| analyze_commits "in last $DAYS days" "$TICKET_FILTER" "$AUTHOR_FILTER" --since="$DAYS days ago" | |
| fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment