diff --git a/git-quick-stats b/git-quick-stats index 952206a..2228ad6 100755 --- a/git-quick-stats +++ b/git-quick-stats @@ -14,8 +14,7 @@ set -o errexit # If $_GIT_SINCE is never set, look at the repository to find the first date. # NOTE: previously this put the date at the fixed GIT epoch (May 2005) _since=${_GIT_SINCE:-} -if [[ -n "${_since}" ]]; -then +if [[ -n "${_since}" ]]; then _since="--since=$_since" else _since="--since=$(git log --reverse --format='%ad' --date=iso | head -n1)" @@ -25,8 +24,7 @@ fi # If $_GIT_UNTIL is never set, choose the latest system # time from the user's current environment _until=${_GIT_UNTIL:-} -if [[ -n "${_until}" ]]; -then +if [[ -n "${_until}" ]]; then _until="--until=$_until" else _until="--until=$(LC_TIME=C date '+%a, %d %b %Y %H:%M:%S %Z')" @@ -35,8 +33,7 @@ fi # Set files or directories to be excluded in stats # If $_GIT_PATHSPEC is not set, shift over the option completely _pathspec=${_GIT_PATHSPEC:-} -if [[ -n "${_pathspec}" ]]; -then +if [[ -n "${_pathspec}" ]]; then _pathspec="-- $_pathspec" else _pathspec="--" @@ -47,11 +44,9 @@ fi # Enable shows regular commits together with normal commits _merges=${_GIT_MERGE_VIEW:-} _merges=$(echo "$_merges" | awk '{print tolower($0)}') -if [[ "${_merges}" == "exclusive" ]]; -then +if [[ "${_merges}" == "exclusive" ]]; then _merges="--merges" -elif [[ "${_merges}" == "enable" ]]; -then +elif [[ "${_merges}" == "enable" ]]; then _merges="" else _merges="--no-merges" @@ -59,8 +54,7 @@ fi # Limit git log output _limit=${_GIT_LIMIT:-} -if [[ -n "${_limit}" ]]; -then +if [[ -n "${_limit}" ]]; then _limit=$_limit else _limit=10 @@ -68,8 +62,7 @@ fi # Log options _log_options=${_GIT_LOG_OPTIONS:-} -if [[ -n "${_log_options}" ]]; -then +if [[ -n "${_log_options}" ]]; then _log_options=$_log_options else _log_options="" @@ -77,8 +70,7 @@ fi # Ignore author regex _ignore_authors=${_GIT_IGNORE_AUTHORS:-} -if [[ -n "${_ignore_authors}" ]]; -then +if [[ -n "${_ignore_authors}" ]]; then _ignore_authors=$_ignore_authors else _ignore_authors="" @@ -87,8 +79,7 @@ fi # Sort by field and order for contribution stats _GIT_SORT_BY=${_GIT_SORT_BY:-name-asc} # If the user has not set a sort order, default to name-asc -if [[ ! "$_GIT_SORT_BY" =~ ^(name|commits|insertions|deletions|lines)-(asc|desc)$ ]]; -then +if [[ ! "$_GIT_SORT_BY" =~ ^(name|commits|insertions|deletions|lines)-(asc|desc)$ ]]; then echo "Invalid sort option: $_GIT_SORT_BY. Defaulting to 'name-asc'." _GIT_SORT_BY="name-asc" fi @@ -113,25 +104,40 @@ function commitsCalendarByAuthor() { --date=iso --author="$author" "$_since" "$_until" $_log_options \ --pretty='%ad' $_pathspec | awk ' { - split($0, a, " "); # a[1] = YYYY-MM-DD - split(a[1], date_fields, "-"); mon = date_fields[2] + 0; + split($0, a, " "); + # a[1] = YYYY-MM-DD + split(a[1], date_fields, "-"); + mon = date_fields[2] + 0; cmd = "date -d \"" a[1] "\" +%u"; cmd | getline weekday; - close(cmd); # weekday: 1=Mon, ..., 7=Sun - count[weekday][mon]++; } + close(cmd); + # weekday: 1=Mon, ..., 7=Sun + count[weekday][mon]++; + } END { # Output matrix for (d=1; d<=7; d++) { - if (d==1) printf "Mon "; else if (d==2) printf "Tue "; - else if (d==3) printf "Wed "; else if (d==4) printf "Thu "; - else if (d==5) printf "Fri "; else if (d==6) printf "Sat "; - else if (d==7) printf "Sun "; for (m=1; m<=12; m++) { - c = count[d][m]+0; if (c==0) out="..."; - else if (c<=9) out="░░░"; - else if (c<=19) out="▒▒▒"; else out="▓▓▓"; + if (d==1) printf "Mon "; + else if (d==2) printf "Tue "; + else if (d==3) printf "Wed "; + else if (d==4) printf "Thu "; + else if (d==5) printf "Fri "; + else if (d==6) printf "Sat "; + else if (d==7) printf "Sun "; + for (m=1; m<=12; m++) { + c = count[d][m]+0; + if (c==0) + out="..."; + else if (c<=9) + out="░░░"; + else if (c<=19) + out="▒▒▒"; + else + out="▓▓▓"; printf "%s%s", out, (m<12?" ":"\n"); } } - printf "\nLegend: ... = 0 ░░░ = 1–9 ▒▒▒ = 10–19 ▓▓▓ = 20+ commits\n"; } + printf "\nLegend: ... = 0 ░░░ = 1–9 ▒▒▒ = 10–19 ▓▓▓ = 20+ commits\n"; + } ' } @@ -200,8 +206,9 @@ SYNOPSIS DESCRIPTION Any git repository contains tons of information about commits, contributors, and files. Extracting this information is not always trivial, mostly because - of a gadzillion options to a gadzillion git commands. This program allows - you to see detailed information about a git repository. + of a gadzillion options to a gadzillion git commands. + + This program allows you to see detailed information about a git repository. GENERATE OPTIONS -T, --detailed-git-stats @@ -274,7 +281,7 @@ ADDITIONAL USAGE ex: export _GIT_BRANCH=master You can set _GIT_IGNORE_AUTHORS to filter out specific authors ex: export _GIT_IGNORE_AUTHORS=\"(author1|author2)\" - You can sort contribution stats by field name, commits, insertions, deletions, or lines - total lines changed and order - asc, desc. e.g.: commits-desc + You can sort contribution stats by field name, commits, insertions, deletions, or lines - total lines changed and order - asc, desc ex: export _GIT_SORT_BY=name-asc" } @@ -298,8 +305,7 @@ function showMenu() { EXIT_TXT="" # Adjustable color menu option - if [[ "${_theme}" == "legacy" ]]; - then + if [[ "${_theme}" == "legacy" ]]; then TITLES="${BOLD}${RED}" TEXT="${NORMAL}${CYAN}" NUMS="${BOLD}${YELLOW}" @@ -346,8 +352,7 @@ function showMenu() { } filter_ignored_authors() { - if [[ -n "$_ignore_authors" ]]; - then + if [[ -n "$_ignore_authors" ]]; then grep -Ev "$_ignore_authors" else cat @@ -359,7 +364,7 @@ filter_ignored_authors() { ################################################################################ # DESC: Shows detailed contribution stats per author by parsing every commit in -# the repo and outputting their contribution stats, including bar graphs. +# the repo and outputting their contribution stats. # ARGS: $branch (optional): Users can specify an alternative branch instead of # the current default one # OUTS: None @@ -370,11 +375,9 @@ function detailedGitStats() { local _branch="" # Check if requesting for a specific branch - if [[ -n "${branch}" ]]; - then + if [[ -n "${branch}" ]]; then # Check if branch exist - if [[ $(git show-ref refs/heads/"${branch}") ]] ; - then + if [[ $(git show-ref refs/heads/"${branch}") ]] ; then is_branch_existing=true _branch="${branch}" else @@ -384,11 +387,9 @@ function detailedGitStats() { fi # Prompt message - if [[ "${is_branch_existing}" && -n "${_branch}" ]]; - then + if [[ "${is_branch_existing}" && -n "${_branch}" ]]; then optionPicked "Contribution stats (by author) on ${_branch} branch:" - elif [[ -n "${branch}" && -z "${_branch}" ]]; - then + elif [[ -n "${branch}" && -z "${_branch}" ]]; then optionPicked "Branch ${branch} does not exist." optionPicked "Contribution stats (by author) on the current branch:" else @@ -554,8 +555,7 @@ function changelogs() { local author="${1:-}" local next=$(date +%F) - if [[ -z "${author}" ]]; - then + if [[ -z "${author}" ]]; then optionPicked "Git changelogs:" _author="--author=**" else @@ -576,8 +576,7 @@ function changelogs() { --since="$DATE 00:00:00" --until="$DATE 23:59:59" \ --date-order) - if [[ -n "$commits" ]]; - then + if [[ -n "$commits" ]]; then echo -e "\n[$DATE]" echo "$commits" else @@ -626,8 +625,7 @@ function csvOutput() { local _branch="" # Check if requesting for a specific branch - if [[ -n "${branch}" ]]; - then + if [[ -n "${branch}" ]]; then # Check if branch exist if [[ $(git show-ref refs/heads/"${branch}") ]] ; then @@ -875,8 +873,7 @@ function commitsPerAuthor() { $_merges "$_since" "$_until" $_log_options \ | grep -i '^ Co-Authored-by:' | cut -c21-) - if [[ -z "${coAuthorCommits}" ]]; - then + if [[ -z "${coAuthorCommits}" ]]; then allCommits="${authorCommits}" else allCommits="${authorCommits}\n${coAuthorCommits}" @@ -918,8 +915,7 @@ function parse_year() { local default_git_date_regex # Handle the raw UNIX timestamp format i.e. 1697375696 +0000 - if [[ "$date_str" =~ ^[0-9]+(\ [+-][0-9]{4})?$ ]]; - then + if [[ "$date_str" =~ ^[0-9]+(\ [+-][0-9]{4})?$ ]]; then timestamp=$(echo "$date_str" | awk '{print $1}') year=$(date -d "@$timestamp" '+%Y' 2>/dev/null) else @@ -934,12 +930,10 @@ function parse_year() { default_git_date_regex+='[0-9]{4}\ ' # Year default_git_date_regex+='[+-][0-9]{4}$' # Timezone offset - if [[ "$date_str" =~ $default_git_date_regex ]]; - then + if [[ "$date_str" =~ $default_git_date_regex ]]; then # Move the year before the time to match a format that Date can parse date_str=$(echo "$date_str" | awk '{print $1, $2, $3, $5, $4, $6}') - elif [[ "$date_str" =~ ^[0-9]{1,2}/[0-9]{1,2}/[0-9]{2,4} ]]; - then + elif [[ "$date_str" =~ ^[0-9]{1,2}/[0-9]{1,2}/[0-9]{2,4} ]]; then # Handle DD/MM/YYYY format date_str=$(echo "$date_str" | awk -F'/' '{print $2"/"$1"/"$3}') fi @@ -971,12 +965,10 @@ function commitsByYear() { # Add time strings to make these a touch more robust for year in $(seq "$startYear" "$endYear"); do - if [[ "$year" = "$startYear" ]]; - then + if [[ "$year" = "$startYear" ]]; then __since=$_since __until="--until=$year-12-31 23:59:59" - elif [[ "$year" = "$endYear" ]]; - then + elif [[ "$year" = "$endYear" ]]; then __since="--since=$year-01-01 00:00:00" __until=$_until else @@ -999,11 +991,13 @@ function commitsByYear() { } END{ for (year in count) { - s="|"; if (total > 0) { + s="|"; + if (total > 0) { percent = ((count[year] / total) * 100) / 1.25; for (i = 1; i <= percent; ++i) { s=s"█" } - printf( "\t%s\t%-0s\t%s\n", year, count[year], s ); } + printf( "\t%s\t%-0s\t%s\n", year, count[year], s ); + } } }' | sort } @@ -1029,11 +1023,13 @@ function commitsByMonth() { } END{ for (month in count) { - s="|"; if (total > 0) { + s="|"; + if (total > 0) { percent = ((count[month] / total) * 100) / 1.25; for (i = 1; i <= percent; ++i) { s=s"█" } - printf( "\t%s\t%-0s\t%s\n", month, count[month], s ); } + printf( "\t%s\t%-0s\t%s\n", month, count[month], s ); + } } }' | LC_TIME="en_EN.UTF-8" sort -M } @@ -1047,8 +1043,7 @@ function commitsByWeekday() { local author="${1:-}" local _author="" - if [[ -z "${author}" ]]; - then + if [[ -z "${author}" ]]; then optionPicked "Git commits by weekday:" _author="--author=**" else @@ -1073,10 +1068,12 @@ function commitsByWeekday() { END{ for (day in count) { s="|"; if (total > 0) { - percent = ((count[day] / total) * 100) / 1.25; for (i = 1; i <= percent; ++i) { + percent = ((count[day] / total) * 100) / 1.25; + for (i = 1; i <= percent; ++i) { s=s"█" } - printf("\t%s\t%s\t%-0s\t%s\n", substr(day,0,1), substr(day,3,5), count[day], s); } + printf("\t%s\t%s\t%-0s\t%s\n", substr(day,0,1), substr(day,3,5), count[day], s); + } } }' | sort -k 1 -n | awk '{$1=""}1' | awk '{$1=$1}1' \ | awk '{printf("\t%s\t%s\t%s\n", $1, $2, $3)}' @@ -1091,8 +1088,7 @@ function commitsByHour() { local author="${1:-}" local _author="" - if [[ -z "${author}" ]]; - then + if [[ -z "${author}" ]]; then optionPicked "Git commits by hour:" _author="--author=**" else @@ -1113,11 +1109,13 @@ function commitsByHour() { } END{ for (hour in count) { - s="|"; if (total > 0) { + s="|"; + if (total > 0) { percent = ((count[hour] / total) * 100) / 1.25; for (i = 1; i <= percent; ++i) { s=s"█" } - printf( "\t%s\t%-0s\t%s\n", hour, count[hour], s ); } + printf( "\t%s\t%-0s\t%s\n", hour, count[hour], s ); + } } }' | sort } @@ -1131,8 +1129,7 @@ function commitsByTimezone() { local author="${1:-}" local _author="" - if [[ -z "${author}" ]]; - then + if [[ -z "${author}" ]]; then optionPicked "Git commits by timezone:" _author="--author=**" else diff --git a/tests/commands_test.sh b/tests/commands_test.sh index 447e7fb..bf981b8 100755 --- a/tests/commands_test.sh +++ b/tests/commands_test.sh @@ -23,8 +23,9 @@ SYNOPSIS DESCRIPTION Any git repository contains tons of information about commits, contributors, and files. Extracting this information is not always trivial, mostly because - of a gadzillion options to a gadzillion git commands. This program allows - you to see detailed information about a git repository. + of a gadzillion options to a gadzillion git commands. + + This program allows you to see detailed information about a git repository. GENERATE OPTIONS -T, --detailed-git-stats @@ -80,11 +81,11 @@ SUGGEST OPTIONS ADDITIONAL USAGE You can set _GIT_SINCE and _GIT_UNTIL to limit the git time log - ex: export _GIT_SINCE="2017-01-20" + ex: export _GIT_SINCE=\"2017-01-20\" You can set _GIT_LIMIT for limited output log ex: export _GIT_LIMIT=20 You can set _GIT_LOG_OPTIONS for git log options - ex: export _GIT_LOG_OPTIONS="--ignore-all-space --ignore-blank-lines" + ex: export _GIT_LOG_OPTIONS=\"--ignore-all-space --ignore-blank-lines\" You can exclude directories or files from the stats by using pathspec ex: export _GIT_PATHSPEC=':!pattern' You can set _GIT_MERGE_VIEW to view merge commits with normal commits @@ -97,7 +98,7 @@ ADDITIONAL USAGE ex: export _GIT_BRANCH=master You can set _GIT_IGNORE_AUTHORS to filter out specific authors ex: export _GIT_IGNORE_AUTHORS=\"(author1|author2)\" - You can sort contribution stats by field name, commits, insertions, deletions, or lines - total lines changed and order - asc, desc. e.g.: commits-desc + You can sort contribution stats by field name, commits, insertions, deletions, or lines - total lines changed and order - asc, desc ex: export _GIT_SORT_BY=name-asc" assert_raises "$src fail" 1