From 8f1e0156d4c47497453a234fe31ca299a259796b Mon Sep 17 00:00:00 2001 From: Matt Hunter Date: Sun, 1 Mar 2026 01:06:55 -0500 Subject: Refactor rc config file management All commands which source content from one of the rc files are collected together at the bottom of the script, in the portion that runs before prompt rendering. Attempt to source from any and all of the files that happen to exist, instead of just taking the first that we find. This allows for instance, the .bash rc file to provide only bash-specific additions that are combined with variables present in .gitradarrc. However, a new ".gitsonarrc" file is now recognized as well whose use should be preferred by new users. File load precedence is such that ".gitsonarrc", if present, has the final say on what variables to use. To improve portability, "source" statements are converted to the POSIX-compliant "." syntax. As part of this code reorganization, the get_fetch_time() function is removed - logic merged into the fetch() function. Signed-off-by: Matt Hunter --- git-sonar | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/git-sonar b/git-sonar index b2d140e..2ff238f 100755 --- a/git-sonar +++ b/git-sonar @@ -7,27 +7,8 @@ GIT_SONAR_VERSION="v0.8.1" dot_git="" -rcfile_path="$HOME" - -get_fetch_time() { - if [ -f "$rcfile_path/.gitradarrc.bash" ]; then - source "$rcfile_path/.gitradarrc.bash" - elif [ -f "$rcfile_path/.gitradarrc.zsh" ]; then - source "$rcfile_path/.gitradarrc.zsh" - elif [ -f "$rcfile_path/.gitradarrc" ]; then - source "$rcfile_path/.gitradarrc" - fi - - FETCH_TIME="${GIT_RADAR_FETCH_TIME:-"$((5 * 60))"}" - echo "$FETCH_TIME" - -} prepare_colors() { - if [ -f "$rcfile_path/.gitradarrc" ]; then - source "$rcfile_path/.gitradarrc" - fi - PRINT_F_OPTION="" COLOR_REMOTE_AHEAD="\x01${GIT_RADAR_COLOR_REMOTE_AHEAD:-"\\033[1;32m"}\x02" @@ -109,8 +90,7 @@ time_to_update() { } fetch() { - # Gives $FETCH_TIME a value - get_fetch_time + FETCH_TIME="${GIT_RADAR_FETCH_TIME:-"$((5 * 60))"}" if time_to_update "$FETCH_TIME"; then record_timestamp @@ -576,6 +556,12 @@ fi # Guard all active operations by this is_repo check if is_repo; then + # Merge configuration from accepted RC files + [ -f "$HOME/.gitradarrc" ] && . "$HOME/.gitradarrc" + [ -f "$HOME/.gitradarrc.bash" ] && . "$HOME/.gitradarrc.bash" + [ -f "$HOME/.gitradarrc.zsh" ] && . "$HOME/.gitradarrc.zsh" + [ -f "$HOME/.gitsonarrc" ] && . "$HOME/.gitsonarrc" + [ -n "$do_fetch" ] && fetch >/dev/null 2>&1 prepare_colors render_prompt -- cgit v1.2.3 From 8d429259e3fb9c22bc3a3935bc3d41417dadedf5 Mon Sep 17 00:00:00 2001 From: Matt Hunter Date: Fri, 6 Mar 2026 15:08:05 -0500 Subject: Refactor autofetch logic Code for handling the auto background fetch is merged down to 1 function, and various changes are made to improve portability and POSIX compliance. The "lastupdatetime" file now stores the unix timestamp in its content, rather than the mtime timestamp. This will provide better platform cross-compatibility, and allows us to drop some code which trys to handle different styles of the stat command. Furthermore, the path to this file (or the .git directory) is no longer cached, since it only needs to be obtained by the script once in this spot. The `[ "$timestamp" -eq "$timestamp" ]` syntax is used to confirm that the content of the "lastupdatetime" file is an integer. This will fail on first encounter with a repository, or if migrating from the old timestamp-based format, or if the file was just mucked with, in which case $timestamp is forced to 0, and a fetch will very likely just occur on the spot. This will fixup the file by writing a new timestamp out to it. Signed-off-by: Matt Hunter --- git-sonar | 52 +++++++--------------------------------------------- 1 file changed, 7 insertions(+), 45 deletions(-) diff --git a/git-sonar b/git-sonar index 2ff238f..1f7b7e8 100755 --- a/git-sonar +++ b/git-sonar @@ -6,8 +6,6 @@ GIT_SONAR_VERSION="v0.8.1" -dot_git="" - prepare_colors() { PRINT_F_OPTION="" @@ -43,58 +41,22 @@ prepare_colors() { } -dot_git() { - if [ -n "$dot_git" ]; then - # cache dot_git to save calls to rev-parse - printf '%s' "$dot_git" - elif [ -d .git ]; then - dot_git=".git" - printf '%s' $dot_git - else - dot_git="$(git rev-parse --git-dir 2>/dev/null)" - printf '%s' "$dot_git" - fi -} - is_repo() { git-precheck --quiet [ $? -lt 4 ] } -record_timestamp() { - touch "$(dot_git)/lastupdatetime" -} - -timestamp() { - if [[ $OSTYPE == darwin* ]]; then - printf '%s' "$(stat -f%m "$(dot_git)/lastupdatetime" 2>/dev/null || printf '%s' "0")" - else - printf '%s' "$(stat -c %Y "$(dot_git)/lastupdatetime" 2>/dev/null || printf '%s' "0")" - fi -} - -time_now() { - printf '%s' "$(date +%s)" -} - -time_to_update() { - last_time_updated="${1:-$FETCH_TIME}" - local timesincelastupdate="$(($(time_now) - $(timestamp)))" - if (( $timesincelastupdate > $last_time_updated )); then - # time to update return 0 (which is true) - return 0 - else - # not time to update return 1 (which is false) - return 1 - fi -} - fetch() { FETCH_TIME="${GIT_RADAR_FETCH_TIME:-"$((5 * 60))"}" + TS_FILE="$(git rev-parse --git-path lastupdatetime 2>/dev/null)" + + now="$(date '+%s')" + timestamp="$(cat "$TS_FILE" 2>/dev/null)" + [ "$timestamp" -eq "$timestamp" ] >/dev/null 2>&1 || timestamp="0" - if time_to_update "$FETCH_TIME"; then - record_timestamp + if [ "$((now - timestamp))" -ge "$FETCH_TIME" ]; then nohup git fetch --quiet >/dev/null 2>&1 & + echo "$now" >"$TS_FILE" fi } -- cgit v1.2.3 From 08ad67de221f737457cb8efc9bf02707d2aca549 Mon Sep 17 00:00:00 2001 From: Matt Hunter Date: Sat, 7 Mar 2026 18:50:52 -0500 Subject: Remove shell regex evaluation Tests performed with `[[ ]]` are not supported in POSIX-compliant shell. However, regex evaluation with the `=~` operator is a specific bashism which has no direct counterpart in POSIX, so I wanted to handle these cases in their own patch. We can simply use grep to evaluate these tests instead. The same regex syntax is supported. Signed-off-by: Matt Hunter --- git-sonar | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/git-sonar b/git-sonar index 1f7b7e8..45baf13 100755 --- a/git-sonar +++ b/git-sonar @@ -373,7 +373,7 @@ render_prompt() { sed_pre="%{\(\([^%^{^}]*\)\:\)\{0,1\}" sed_post="\(\:\([^%^{^}]*\)\)\{0,1\}}" - if [[ $PROMPT_FORMAT =~ ${if_pre}condition${if_post} ]]; then + if echo "$PROMPT_FORMAT" | grep -qE "${if_pre}condition${if_post}"; then condition_result="$(repo_special_condition)" if [[ -n "$condition_result" ]]; then condition_sed="s/${sed_pre}condition${sed_post}/\2${condition_result}\4/" @@ -381,7 +381,7 @@ render_prompt() { condition_sed="s/${sed_pre}condition${sed_post}//" fi fi - if [[ $PROMPT_FORMAT =~ ${if_pre}missingups${if_post} ]]; then + if echo "$PROMPT_FORMAT" | grep -qE "${if_pre}missingups${if_post}"; then missingups_result="$(color_missing_upstream)" if [[ -n "$missingups_result" ]]; then missingups_sed="s/${sed_pre}missingups${sed_post}/\2${missingups_result}\4/" @@ -389,7 +389,7 @@ render_prompt() { missingups_sed="s/${sed_pre}missingups${sed_post}//" fi fi - if [[ $PROMPT_FORMAT =~ ${if_pre}remote${if_post} ]]; then + if echo "$PROMPT_FORMAT" | grep -qE "${if_pre}remote${if_post}"; then remote_result="$(color_remote_commits)" if [[ -n "$remote_result" ]]; then remote_sed="s/${sed_pre}remote${sed_post}/\2${remote_result}\4/" @@ -397,7 +397,7 @@ render_prompt() { remote_sed="s/${sed_pre}remote${sed_post}//" fi fi - if [[ $PROMPT_FORMAT =~ ${if_pre}branch${if_post} ]]; then + if echo "$PROMPT_FORMAT" | grep -qE "${if_pre}branch${if_post}"; then branch_result="$(readable_branch_name | sed -e 's/\//\\\//g')" if [[ -n "$branch_result" ]]; then branch_sed="s/${sed_pre}branch${sed_post}/\2${branch_result}\4/" @@ -405,7 +405,7 @@ render_prompt() { branch_sed="s/${sed_pre}branch${sed_post}//" fi fi - if [[ $PROMPT_FORMAT =~ ${if_pre}local${if_post} ]]; then + if echo "$PROMPT_FORMAT" | grep -qE "${if_pre}local${if_post}"; then local_result="$(color_local_commits)" if [[ -n "$local_result" ]]; then local_sed="s/${sed_pre}local${sed_post}/\2$local_result\4/" @@ -413,7 +413,7 @@ render_prompt() { local_sed="s/${sed_pre}local${sed_post}//" fi fi - if [[ $PROMPT_FORMAT =~ ${if_pre}changes${if_post} ]]; then + if echo "$PROMPT_FORMAT" | grep -qE "${if_pre}changes${if_post}"; then changes_result="$(color_changes_status)" if [[ -n "$changes_result" ]]; then changes_sed="s/${sed_pre}changes${sed_post}/\2${changes_result}\4/" @@ -421,7 +421,7 @@ render_prompt() { changes_sed="s/${sed_pre}changes${sed_post}//" fi fi - if [[ $PROMPT_FORMAT =~ ${if_pre}stash${if_post} ]]; then + if echo "$PROMPT_FORMAT" | grep -qE "${if_pre}stash${if_post}"; then stash_result="$(stash_status)" if [[ -n "$stash_result" ]]; then stash_sed="s/${sed_pre}stash${sed_post}/\2${stash_result}\4/" -- cgit v1.2.3 From 62c225c40ffebcd3c35f3a9917f1a4dff4b81137 Mon Sep 17 00:00:00 2001 From: Matt Hunter Date: Sun, 8 Mar 2026 14:45:31 -0400 Subject: Remove [[ ]] tests Tests using the `[[ ]]` syntax are not supported in POSIX-compliant shell. Remove the rest of these cases which more directly translate to standard tests. Some small cleanups are made along the way. Signed-off-by: Matt Hunter --- git-sonar | 54 +++++++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/git-sonar b/git-sonar index 45baf13..31b6c6f 100755 --- a/git-sonar +++ b/git-sonar @@ -72,11 +72,11 @@ remote_branch_name() { local localRef local remote localRef="$(branch_name)" - remote="$(git config --get "branch.$localRef.remote")" - if [[ -n $remote ]]; then + remote="$(git config --get "branch.${localRef}.remote")" + if [ -n "$remote" ]; then local remoteBranch remoteBranch="$(git config --get "branch.${localRef}.merge" | sed -e 's/^refs\/heads\///')" - if [[ -n $remoteBranch ]]; then + if [ -n "$remoteBranch" ]; then printf '%s/%s' "$remote" "$remoteBranch" return 0 else @@ -89,7 +89,7 @@ remote_branch_name() { commits_behind_of_remote() { remote_branch=${1:-"$(remote_branch_name)"} - if [[ -n "$remote_branch" ]]; then + if [ -n "$remote_branch" ]; then git rev-list --left-only --count "${remote_branch}...HEAD" 2>/dev/null else printf '%s' "0" @@ -98,7 +98,7 @@ commits_behind_of_remote() { commits_ahead_of_remote() { remote_branch=${1:-"$(remote_branch_name)"} - if [[ -n "$remote_branch" ]]; then + if [ -n "$remote_branch" ]; then git rev-list --right-only --count "${remote_branch}...HEAD" 2>/dev/null else printf '%s' "0" @@ -107,10 +107,10 @@ commits_ahead_of_remote() { determine_tracked_remote() { by_branch=$(git config --local branch."$(git rev-parse --abbrev-ref HEAD)".git-radar-tracked-remote) - [[ ! -z "$by_branch" ]] && echo "$by_branch" && return 0 + [ -n "$by_branch" ] && echo "$by_branch" && return 0 by_config=$(git config --local git-radar.tracked-remote) - [[ ! -z "$by_config" ]] && echo "$by_config" && return 0 + [ -n "$by_config" ] && echo "$by_config" && return 0 echo "origin/master" } @@ -118,7 +118,7 @@ determine_tracked_remote() { remote_behind_of_master() { remote_branch=${1:-"$(remote_branch_name)"} tracked_remote=$(determine_tracked_remote) - if [[ -n "$remote_branch" && "$remote_branch" != "$tracked_remote" ]]; then + if [ -n "$remote_branch" ] && [ "$remote_branch" != "$tracked_remote" ]; then git rev-list --left-only --count "${tracked_remote}...${remote_branch}" 2>/dev/null || printf '%s' "0" else printf '%s' "0" @@ -128,7 +128,7 @@ remote_behind_of_master() { remote_ahead_of_master() { remote_branch=${1:-"$(remote_branch_name)"} tracked_remote=$(determine_tracked_remote) - if [[ -n "$remote_branch" && "$remote_branch" != "$tracked_remote" ]]; then + if [ -n "$remote_branch" ] && [ "$remote_branch" != "$tracked_remote" ]; then git rev-list --right-only --count "${tracked_remote}...${remote_branch}" 2>/dev/null || printf '%s' "0" else printf '%s' "0" @@ -256,7 +256,7 @@ color_changes_status() { porcelain="$(porcelain_status)" local changes="" - if [[ -n "$porcelain" ]]; then + if [ -n "$porcelain" ]; then local staged_changes local unstaged_changes local untracked_changes @@ -265,19 +265,19 @@ color_changes_status() { unstaged_changes="$(unstaged_status "$porcelain" "$COLOR_CHANGES_UNSTAGED" "$RESET_COLOR_CHANGES")" untracked_changes="$(untracked_status "$porcelain" "$COLOR_CHANGES_UNTRACKED" "$RESET_COLOR_CHANGES")" conflicted_changes="$(conflicted_status "$porcelain" "$COLOR_CHANGES_CONFLICTED" "$RESET_COLOR_CHANGES")" - if [[ -n "$staged_changes" ]]; then + if [ -n "$staged_changes" ]; then staged_changes="$separator$staged_changes" fi - if [[ -n "$unstaged_changes" ]]; then + if [ -n "$unstaged_changes" ]; then unstaged_changes="$separator$unstaged_changes" fi - if [[ -n "$conflicted_changes" ]]; then + if [ -n "$conflicted_changes" ]; then conflicted_changes="$separator$conflicted_changes" fi - if [[ -n "$untracked_changes" ]]; then + if [ -n "$untracked_changes" ]; then untracked_changes="$separator$untracked_changes" fi @@ -296,11 +296,11 @@ color_local_commits() { local_ahead="$(commits_ahead_of_remote "$remote_branch")" local_behind="$(commits_behind_of_remote "$remote_branch")" - if [[ "$local_behind" -gt "0" && "$local_ahead" -gt "0" ]]; then + if [ "$local_behind" -gt 0 ] && [ "$local_ahead" -gt 0 ]; then local_commits="$local_behind$yellow_diverged_arrow$local_ahead" - elif [[ "$local_behind" -gt "0" ]]; then + elif [ "$local_behind" -gt 0 ]; then local_commits="$local_behind$red_behind_arrow" - elif [[ "$local_ahead" -gt "0" ]]; then + elif [ "$local_ahead" -gt 0 ]; then local_commits="$local_ahead$green_ahead_arrow" fi fi @@ -327,11 +327,11 @@ color_remote_commits() { remote_ahead="$(remote_ahead_of_master "$remote_branch")" remote_behind="$(remote_behind_of_master "$remote_branch")" - if [[ "$remote_behind" -gt "0" && "$remote_ahead" -gt "0" ]]; then + if [ "$remote_behind" -gt 0 ] && [ "$remote_ahead" -gt 0 ]; then remote="$MASTER_SYMBOL$remote_behind$yellow_diverged_arrow$remote_ahead" - elif [[ "$remote_ahead" -gt "0" ]]; then + elif [ "$remote_ahead" -gt 0 ]; then remote="$MASTER_SYMBOL$green_ahead_arrow$remote_ahead" - elif [[ "$remote_behind" -gt "0" ]]; then + elif [ "$remote_behind" -gt 0 ]; then remote="$MASTER_SYMBOL$remote_behind$red_behind_arrow" fi fi @@ -375,7 +375,7 @@ render_prompt() { if echo "$PROMPT_FORMAT" | grep -qE "${if_pre}condition${if_post}"; then condition_result="$(repo_special_condition)" - if [[ -n "$condition_result" ]]; then + if [ -n "$condition_result" ]; then condition_sed="s/${sed_pre}condition${sed_post}/\2${condition_result}\4/" else condition_sed="s/${sed_pre}condition${sed_post}//" @@ -383,7 +383,7 @@ render_prompt() { fi if echo "$PROMPT_FORMAT" | grep -qE "${if_pre}missingups${if_post}"; then missingups_result="$(color_missing_upstream)" - if [[ -n "$missingups_result" ]]; then + if [ -n "$missingups_result" ]; then missingups_sed="s/${sed_pre}missingups${sed_post}/\2${missingups_result}\4/" else missingups_sed="s/${sed_pre}missingups${sed_post}//" @@ -391,7 +391,7 @@ render_prompt() { fi if echo "$PROMPT_FORMAT" | grep -qE "${if_pre}remote${if_post}"; then remote_result="$(color_remote_commits)" - if [[ -n "$remote_result" ]]; then + if [ -n "$remote_result" ]; then remote_sed="s/${sed_pre}remote${sed_post}/\2${remote_result}\4/" else remote_sed="s/${sed_pre}remote${sed_post}//" @@ -399,7 +399,7 @@ render_prompt() { fi if echo "$PROMPT_FORMAT" | grep -qE "${if_pre}branch${if_post}"; then branch_result="$(readable_branch_name | sed -e 's/\//\\\//g')" - if [[ -n "$branch_result" ]]; then + if [ -n "$branch_result" ]; then branch_sed="s/${sed_pre}branch${sed_post}/\2${branch_result}\4/" else branch_sed="s/${sed_pre}branch${sed_post}//" @@ -407,7 +407,7 @@ render_prompt() { fi if echo "$PROMPT_FORMAT" | grep -qE "${if_pre}local${if_post}"; then local_result="$(color_local_commits)" - if [[ -n "$local_result" ]]; then + if [ -n "$local_result" ]; then local_sed="s/${sed_pre}local${sed_post}/\2$local_result\4/" else local_sed="s/${sed_pre}local${sed_post}//" @@ -415,7 +415,7 @@ render_prompt() { fi if echo "$PROMPT_FORMAT" | grep -qE "${if_pre}changes${if_post}"; then changes_result="$(color_changes_status)" - if [[ -n "$changes_result" ]]; then + if [ -n "$changes_result" ]; then changes_sed="s/${sed_pre}changes${sed_post}/\2${changes_result}\4/" else changes_sed="s/${sed_pre}changes${sed_post}//" @@ -423,7 +423,7 @@ render_prompt() { fi if echo "$PROMPT_FORMAT" | grep -qE "${if_pre}stash${if_post}"; then stash_result="$(stash_status)" - if [[ -n "$stash_result" ]]; then + if [ -n "$stash_result" ]; then stash_sed="s/${sed_pre}stash${sed_post}/\2${stash_result}\4/" else stash_sed="s/${sed_pre}stash${sed_post}//" -- cgit v1.2.3 From 8960c6297eece7494da8d94076ecda87b02a9402 Mon Sep 17 00:00:00 2001 From: Matt Hunter Date: Sun, 8 Mar 2026 15:55:16 -0400 Subject: Remove use of "local" keyword The "local" keyword for scoping variables is undefined in POSIX shell. Signed-off-by: Matt Hunter --- git-sonar | 81 +++++++++++++++++++++++---------------------------------------- 1 file changed, 29 insertions(+), 52 deletions(-) diff --git a/git-sonar b/git-sonar index 31b6c6f..12b3fea 100755 --- a/git-sonar +++ b/git-sonar @@ -69,12 +69,9 @@ branch_name() { } remote_branch_name() { - local localRef - local remote localRef="$(branch_name)" remote="$(git config --get "branch.${localRef}.remote")" if [ -n "$remote" ]; then - local remoteBranch remoteBranch="$(git config --get "branch.${localRef}.merge" | sed -e 's/^refs\/heads\///')" if [ -n "$remoteBranch" ]; then printf '%s/%s' "$remote" "$remoteBranch" @@ -145,17 +142,11 @@ porcelain_status() { } staged_status() { - local gitStatus=${1:-"$(porcelain_status)"} - local prefix=${2:-""} - local suffix=${3:-""} - - local staged_string="" - local filesModified - local filesAdded - local filesDeleted - local filesRenamed - local filesCopied - local typeChanged + gitStatus="${1:-"$(porcelain_status)"}" + prefix="${2:-""}" + suffix="${3:-""}" + staged_string="" + filesModified="$(printf '%s' "$gitStatus" | grep -oE "M[ACDRM ] " | wc -l | grep -oEi '[1-9][0-9]*')" filesAdded="$(printf '%s' "$gitStatus" | grep -oE "A[MCDR ] " | wc -l | grep -oEi '[1-9][0-9]*')" filesDeleted="$(printf '%s' "$gitStatus" | grep -oE "D[AMCR ] " | wc -l | grep -oEi '[1-9][0-9]*')" @@ -185,14 +176,11 @@ staged_status() { } conflicted_status() { - local gitStatus=${1:-"$(porcelain_status)"} - local prefix=${2:-""} - local suffix=${3:-""} - local conflicted_string="" - - local filesUs - local filesThem - local filesBoth + gitStatus="${1:-"$(porcelain_status)"}" + prefix="${2:-""}" + suffix="${3:-""}" + conflicted_string="" + filesUs="$(printf '%s' "$gitStatus" | grep -oE "[AD]U " | wc -l | grep -oEi '[1-9][0-9]*')" filesThem="$(printf '%s' "$gitStatus" | grep -oE "U[AD] " | wc -l | grep -oEi '[1-9][0-9]*')" filesBoth="$(printf '%s' "$gitStatus" | grep -oE "(UU|AA|DD) " | wc -l | grep -oEi '[1-9][0-9]*')" @@ -210,14 +198,11 @@ conflicted_status() { } unstaged_status() { - local gitStatus=${1:-"$(porcelain_status)"} - local prefix=${2:-""} - local suffix=${3:-""} - local unstaged_string="" - - local filesModified - local filesDeleted - local typeChanged + gitStatus="${1:-"$(porcelain_status)"}" + prefix="${2:-""}" + suffix="${3:-""}" + unstaged_string="" + filesModified="$(printf '%s' "$gitStatus" | grep -oE "[ACDRM ]M " | wc -l | grep -oEi '[1-9][0-9]*')" filesDeleted="$(printf '%s' "$gitStatus" | grep -oE "[AMCR ]D " | wc -l | grep -oEi '[1-9][0-9]*')" typeChanged="$(printf '%s' "$gitStatus" | grep -oE "[AMDR ]T " | wc -l | grep -oEi '[1-9][0-9]*')" @@ -235,12 +220,11 @@ unstaged_status() { } untracked_status() { - local gitStatus=${1:-"$(porcelain_status)"} - local prefix=${2:-""} - local suffix=${3:-""} - local untracked_string="" + gitStatus="${1:-"$(porcelain_status)"}" + prefix="${2:-""}" + suffix="${3:-""}" + untracked_string="" - local filesUntracked filesUntracked="$(printf '%s' "$gitStatus" | grep "?? " | wc -l | grep -oEi '[1-9][0-9]*')" if [ -n "$filesUntracked" ]; then @@ -250,17 +234,11 @@ untracked_status() { } color_changes_status() { - local separator="${1:- }" - - local porcelain + separator="${1:- }" porcelain="$(porcelain_status)" - local changes="" + changes="" if [ -n "$porcelain" ]; then - local staged_changes - local unstaged_changes - local untracked_changes - local conflicted_changes staged_changes="$(staged_status "$porcelain" "$COLOR_CHANGES_STAGED" "$RESET_COLOR_CHANGES")" unstaged_changes="$(unstaged_status "$porcelain" "$COLOR_CHANGES_UNSTAGED" "$RESET_COLOR_CHANGES")" untracked_changes="$(untracked_status "$porcelain" "$COLOR_CHANGES_UNTRACKED" "$RESET_COLOR_CHANGES")" @@ -287,11 +265,11 @@ color_changes_status() { } color_local_commits() { - local green_ahead_arrow="${COLOR_LOCAL_AHEAD}↑$RESET_COLOR_LOCAL" - local red_behind_arrow="${COLOR_LOCAL_BEHIND}↓$RESET_COLOR_LOCAL" - local yellow_diverged_arrow="${COLOR_LOCAL_DIVERGED}⇵$RESET_COLOR_LOCAL" + green_ahead_arrow="${COLOR_LOCAL_AHEAD}↑$RESET_COLOR_LOCAL" + red_behind_arrow="${COLOR_LOCAL_BEHIND}↓$RESET_COLOR_LOCAL" + yellow_diverged_arrow="${COLOR_LOCAL_DIVERGED}⇵$RESET_COLOR_LOCAL" + local_commits="" - local local_commits="" if remote_branch="$(remote_branch_name)"; then local_ahead="$(commits_ahead_of_remote "$remote_branch")" local_behind="$(commits_behind_of_remote "$remote_branch")" @@ -308,7 +286,7 @@ color_local_commits() { } color_missing_upstream() { - local not_upstream="${COLOR_REMOTE_NOT_UPSTREAM}⚡$RESET_COLOR_REMOTE" + not_upstream="${COLOR_REMOTE_NOT_UPSTREAM}⚡$RESET_COLOR_REMOTE" if remote_branch="$(remote_branch_name)"; then if ! git rev-parse "$remote_branch" -- >/dev/null 2>&1; then @@ -318,9 +296,9 @@ color_missing_upstream() { } color_remote_commits() { - local green_ahead_arrow="${COLOR_REMOTE_AHEAD}↑$RESET_COLOR_REMOTE" # "←" - local red_behind_arrow="${COLOR_REMOTE_BEHIND}↓$RESET_COLOR_REMOTE" # "→" - local yellow_diverged_arrow="${COLOR_REMOTE_DIVERGED}⇵$RESET_COLOR_REMOTE" # "⇄" + green_ahead_arrow="${COLOR_REMOTE_AHEAD}↑$RESET_COLOR_REMOTE" # "←" + red_behind_arrow="${COLOR_REMOTE_BEHIND}↓$RESET_COLOR_REMOTE" # "→" + yellow_diverged_arrow="${COLOR_REMOTE_DIVERGED}⇵$RESET_COLOR_REMOTE" # "⇄" remote="" if remote_branch="$(remote_branch_name)"; then @@ -348,7 +326,6 @@ stashed_status() { } stash_status() { - local number_stashes number_stashes="$(stashed_status)" if [ "$number_stashes" -gt 0 ]; then printf $PRINT_F_OPTION "${number_stashes}${COLOR_STASH}≡${RESET_COLOR_STASH}" -- cgit v1.2.3 From 85aaf4533896a1398482559692e34e02366e89a0 Mon Sep 17 00:00:00 2001 From: Matt Hunter Date: Sun, 8 Mar 2026 16:21:47 -0400 Subject: Remove echo flags echo options are undefined in POSIX shell. Signed-off-by: Matt Hunter --- git-sonar | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/git-sonar b/git-sonar index 12b3fea..08a12df 100755 --- a/git-sonar +++ b/git-sonar @@ -439,25 +439,25 @@ usage() { echo " $GIT_SONAR_VERSION" echo "" echo "examples:" - echo -ne " $_git$_master$_endgit" + printf '%b' " $_git$_master$_endgit" echo " # You are on the master branch and everything is clean" - echo -ne " $_git$_not_upstream$_my_branch$_endgit" + printf '%b' " $_git$_not_upstream$_my_branch$_endgit" echo " # Fresh branch that we haven't pushed upstream" - echo -ne " $_git$_my_branch$_endgit 2$_untracked" + printf '%b' " $_git$_my_branch$_endgit 2$_untracked" echo " # Two files created that aren't tracked by git" - echo -ne " $_git$_my_branch$_endgit 1$_added_staged 3$_modified_unstaged" + printf '%b' " $_git$_my_branch$_endgit 1$_added_staged 3$_modified_unstaged" echo " # 1 new file staged to commit and 3 modifications that we still need to \`git add\`" - echo -ne " $_git$_2_from_master$_my_branch 3$_local_up$_endgit" + printf '%b' " $_git$_2_from_master$_my_branch 3$_local_up$_endgit" echo " # 3 commits made locally ready to push up while master is ahead of us by 2" - echo -ne " $_git$_diverged_from_master$_my_branch$_endgit" + printf '%b' " $_git$_diverged_from_master$_my_branch$_endgit" echo " # our commits pushed up, master and my-branch have diverged" - echo -ne " $_git$_detached$_endgit 2${_conflicted_them}3${_conflicted_us}" + printf '%b' " $_git$_detached$_endgit 2${_conflicted_them}3${_conflicted_us}" echo " # mid rebase, we are detached and have 3 conflicts caused by US and 2 caused by THEM" - echo -ne " $_git$_diverged_from_master$_my_branch 3${_local_diverged}5$_endgit" + printf '%b' " $_git$_diverged_from_master$_my_branch 3${_local_diverged}5$_endgit" echo " # rebase complete, our rewritten commits now need pushed up" - echo -ne " $_git$_ahead_master 3 $_my_branch$_endgit" + printf '%b' " $_git$_ahead_master 3 $_my_branch$_endgit" echo " # origin/my-branch is up to date with master and has our 3 commits waiting merge" - echo -ne " $_git$_master$_endgit 3$_stash" + printf '%b' " $_git$_master$_endgit 3$_stash" echo " # You have 3 stashes stored" echo "" -- cgit v1.2.3 From f4636c75050f3ac3208d953c4d88c29d58309bdc Mon Sep 17 00:00:00 2001 From: Matt Hunter Date: Sun, 8 Mar 2026 17:06:44 -0400 Subject: Remove bash string indexing This syntax is undefined in POSIX shell. Instead, use what should be a more robust solution, and literally strip the $separator from the beginning of the string, rather than just hard coding a length. Signed-off-by: Matt Hunter --- git-sonar | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-sonar b/git-sonar index 08a12df..52319b6 100755 --- a/git-sonar +++ b/git-sonar @@ -261,7 +261,7 @@ color_changes_status() { changes="$staged_changes$conflicted_changes$unstaged_changes$untracked_changes" fi - printf $PRINT_F_OPTION "${changes:1}" + printf $PRINT_F_OPTION "${changes#"$separator"}" } color_local_commits() { -- cgit v1.2.3 From 16c03453c1b45ac1817d10442689aa77e3d18a49 Mon Sep 17 00:00:00 2001 From: Matt Hunter Date: Fri, 13 Mar 2026 22:50:01 -0400 Subject: Convert hex character literals to octal The use of "\xHH" characters with echo and printf is an extension to the POSIX spec and not supported by all shells. Replace these with octal character literals like "\000" with 3 digits per byte. Link: https://unix.stackexchange.com/questions/627036 Signed-off-by: Matt Hunter --- git-sonar | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/git-sonar b/git-sonar index 52319b6..38212be 100755 --- a/git-sonar +++ b/git-sonar @@ -9,35 +9,35 @@ GIT_SONAR_VERSION="v0.8.1" prepare_colors() { PRINT_F_OPTION="" - COLOR_REMOTE_AHEAD="\x01${GIT_RADAR_COLOR_REMOTE_AHEAD:-"\\033[1;32m"}\x02" - COLOR_REMOTE_BEHIND="\x01${GIT_RADAR_COLOR_REMOTE_BEHIND:-"\\033[1;31m"}\x02" - COLOR_REMOTE_DIVERGED="\x01${GIT_RADAR_COLOR_REMOTE_DIVERGED:-"\\033[1;33m"}\x02" - COLOR_REMOTE_NOT_UPSTREAM="\x01${GIT_RADAR_COLOR_REMOTE_NOT_UPSTREAM:-"\\033[1;33m"}\x02" + COLOR_REMOTE_AHEAD="\001${GIT_RADAR_COLOR_REMOTE_AHEAD:-"\\033[1;32m"}\002" + COLOR_REMOTE_BEHIND="\001${GIT_RADAR_COLOR_REMOTE_BEHIND:-"\\033[1;31m"}\002" + COLOR_REMOTE_DIVERGED="\001${GIT_RADAR_COLOR_REMOTE_DIVERGED:-"\\033[1;33m"}\002" + COLOR_REMOTE_NOT_UPSTREAM="\001${GIT_RADAR_COLOR_REMOTE_NOT_UPSTREAM:-"\\033[1;33m"}\002" - COLOR_LOCAL_AHEAD="\x01${GIT_RADAR_COLOR_LOCAL_AHEAD:-"\\033[1;32m"}\x02" - COLOR_LOCAL_BEHIND="\x01${GIT_RADAR_COLOR_LOCAL_BEHIND:-"\\033[1;31m"}\x02" - COLOR_LOCAL_DIVERGED="\x01${GIT_RADAR_COLOR_LOCAL_DIVERGED:-"\\033[1;33m"}\x02" + COLOR_LOCAL_AHEAD="\001${GIT_RADAR_COLOR_LOCAL_AHEAD:-"\\033[1;32m"}\002" + COLOR_LOCAL_BEHIND="\001${GIT_RADAR_COLOR_LOCAL_BEHIND:-"\\033[1;31m"}\002" + COLOR_LOCAL_DIVERGED="\001${GIT_RADAR_COLOR_LOCAL_DIVERGED:-"\\033[1;33m"}\002" - COLOR_CHANGES_STAGED="\x01${GIT_RADAR_COLOR_CHANGES_STAGED:-"\\033[1;32m"}\x02" - COLOR_CHANGES_UNSTAGED="\x01${GIT_RADAR_COLOR_CHANGES_UNSTAGED:-"\\033[1;31m"}\x02" - COLOR_CHANGES_CONFLICTED="\x01${GIT_RADAR_COLOR_CHANGES_CONFLICTED:-"\\033[1;33m"}\x02" - COLOR_CHANGES_UNTRACKED="\x01${GIT_RADAR_COLOR_CHANGES_UNTRACKED:-"\\033[1;37m"}\x02" + COLOR_CHANGES_STAGED="\001${GIT_RADAR_COLOR_CHANGES_STAGED:-"\\033[1;32m"}\002" + COLOR_CHANGES_UNSTAGED="\001${GIT_RADAR_COLOR_CHANGES_UNSTAGED:-"\\033[1;31m"}\002" + COLOR_CHANGES_CONFLICTED="\001${GIT_RADAR_COLOR_CHANGES_CONFLICTED:-"\\033[1;33m"}\002" + COLOR_CHANGES_UNTRACKED="\001${GIT_RADAR_COLOR_CHANGES_UNTRACKED:-"\\033[1;37m"}\002" - COLOR_CONDITION="\x01${GIT_RADAR_COLOR_CONDITION:-"\\033[1;33m"}\x02" + COLOR_CONDITION="\001${GIT_RADAR_COLOR_CONDITION:-"\\033[1;33m"}\002" - COLOR_STASH="\x01${GIT_RADAR_COLOR_STASH:-"\\033[1;33m"}\x02" + COLOR_STASH="\001${GIT_RADAR_COLOR_STASH:-"\\033[1;33m"}\002" - COLOR_BRANCH="\x01${GIT_RADAR_COLOR_BRANCH:-"\\033[0m"}\x02" + COLOR_BRANCH="\001${GIT_RADAR_COLOR_BRANCH:-"\\033[0m"}\002" MASTER_SYMBOL="${GIT_RADAR_MASTER_SYMBOL:-""}" # \\x01\\033[0m\\x02\\xF0\\x9D\\x98\\xAE\\x01\\033[0m\\x02 - PROMPT_FORMAT="${GIT_RADAR_FORMAT:-" \\x01\\033[1;30m\\x02git:(\\x01\\033[0m\\x02%{condition: }%{remote: }%{missingups}%{branch}%{ :local}\\x01\\033[1;30m\\x02)\\x01\\033[0m\\x02%{ :stash}%{ :changes}"}" + PROMPT_FORMAT="${GIT_RADAR_FORMAT:-" \\001\\033[1;30m\\002git:(\\001\\033[0m\\002%{condition: }%{remote: }%{missingups}%{branch}%{ :local}\\001\\033[1;30m\\002)\\001\\033[0m\\002%{ :stash}%{ :changes}"}" - RESET_COLOR_LOCAL="\x01${GIT_RADAR_COLOR_LOCAL_RESET:-"\\033[0m"}\x02" - RESET_COLOR_REMOTE="\x01${GIT_RADAR_COLOR_REMOTE_RESET:-"\\033[0m"}\x02" - RESET_COLOR_CHANGES="\x01${GIT_RADAR_COLOR_CHANGES_RESET:-"\\033[0m"}\x02" - RESET_COLOR_BRANCH="\x01${GIT_RADAR_COLOR_BRANCH_RESET:-"\\033[0m"}\x02" - RESET_COLOR_STASH="\x01${GIT_RADAR_COLOR_STASH_RESET:-"\\033[0m"}\x02" - RESET_COLOR_CONDITION="\x01${GIT_RADAR_COLOR_CONDITION_RESET:-"\\033[0m"}\x02" + RESET_COLOR_LOCAL="\001${GIT_RADAR_COLOR_LOCAL_RESET:-"\\033[0m"}\002" + RESET_COLOR_REMOTE="\001${GIT_RADAR_COLOR_REMOTE_RESET:-"\\033[0m"}\002" + RESET_COLOR_CHANGES="\001${GIT_RADAR_COLOR_CHANGES_RESET:-"\\033[0m"}\002" + RESET_COLOR_BRANCH="\001${GIT_RADAR_COLOR_BRANCH_RESET:-"\\033[0m"}\002" + RESET_COLOR_STASH="\001${GIT_RADAR_COLOR_STASH_RESET:-"\\033[0m"}\002" + RESET_COLOR_CONDITION="\001${GIT_RADAR_COLOR_CONDITION_RESET:-"\\033[0m"}\002" } @@ -426,13 +426,13 @@ usage() { _added_staged="\033[1;32mA\033[0m" _modified_unstaged="\033[1;31mM\033[0m" _local_up="\033[1;32m↑\033[0m" - _2_from_master="\xF0\x9D\x98\xAE 2 \033[1;31m→\033[0m " - _diverged_from_master="\xF0\x9D\x98\xAE 2 \033[1;33m⇄\033[0m 3 " + _2_from_master="\360\235\230\256 2 \033[1;31m→\033[0m " + _diverged_from_master="\360\235\230\256 2 \033[1;33m⇄\033[0m 3 " _not_upstream="upstream \033[1;31m⚡\033[0m " _detached="\033[0;37mdetached@94eac67\033[0m" _conflicted_us="\033[1;33mU\033[0m" _conflicted_them="\033[1;33mT\033[0m" - _ahead_master="\xF0\x9D\x98\xAE \033[1;32m←\033[0m" + _ahead_master="\360\235\230\256 \033[1;32m←\033[0m" _local_diverged="\033[1;33m⇵\033[0m" _stash="\033[1;33m≡\033[0m" echo "git-sonar - a heads up display for git" -- cgit v1.2.3 From bce1fbf7cc3e43437e1b77f70cdcb08976137951 Mon Sep 17 00:00:00 2001 From: Matt Hunter Date: Sat, 28 Feb 2026 23:45:59 -0500 Subject: Switch to POSIX shebang line Signed-off-by: Matt Hunter --- git-sonar | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-sonar b/git-sonar index 38212be..172529c 100755 --- a/git-sonar +++ b/git-sonar @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/sh # # git-sonar # -- cgit v1.2.3