From 0b96dee27bff6276f0f435c52327eecbbd0aa4e5 Mon Sep 17 00:00:00 2001 From: Matt Hunter Date: Sat, 21 Feb 2026 01:52:45 -0500 Subject: Add git-precheck script This is an alternative entrypoint primarily intended for use in other scripts. The purpose of git-precheck is to easily determine the state of a git repository before going on to perform additional, possibly disruptive work. git-precheck tries to cover as many bases as possible - odd cases like 'merge in progress', 'cherry-pick in progress', etc. By default, we only exit success (0) if we are in a repo that is completely clean (no file modifications or untracked files present) and has no ongoing operation. Signed-off-by: Matt Hunter --- Makefile | 6 ++-- git-precheck | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 2 deletions(-) create mode 100755 git-precheck diff --git a/Makefile b/Makefile index 95538ac..6edd7f4 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -SOURCE=git-sonar +SOURCE=git-sonar git-precheck PREFIX?=/usr/local PWD=$(shell pwd) @@ -21,7 +21,9 @@ install: $(SOURCE) mkdir -p $(PREFIX)/bin install -m 755 $(SOURCE) $(PREFIX)/bin +# Link each file separately since the full PWD is needed develop: $(SOURCE) @echo 'Symlinking in' $(PREFIX)/bin '...' mkdir -p $(PREFIX)/bin - ln -sf $(PWD)/$(SOURCE) $(PREFIX)/bin + ln -sf $(PWD)/git-sonar $(PREFIX)/bin + ln -sf $(PWD)/git-precheck $(PREFIX)/bin diff --git a/git-precheck b/git-precheck new file mode 100755 index 0000000..9984bbb --- /dev/null +++ b/git-precheck @@ -0,0 +1,94 @@ +#!/bin/sh + +usage() { + echo "git-precheck [--quiet] [--ignore-dirty] [--ignore-untracked]" + echo "" + echo "If the current working directory is inside a git repository, examine" + echo "the repo for any abnormal state and return an exit code indicating" + echo "the status. If unclean, print a line of text describing the" + echo "condition." + echo "" + echo " --quiet" + echo " Don't actually print anything." + echo "" + echo " --ignore-dirty" + echo " Don't consider the presence of uncommitted changes to tracked" + echo " files as an abnormal state." + echo "" + echo " --ignore-untracked" + echo " Don't consider the presence of untracked files as an abnormal" + echo " state." + echo "" + echo " Exit codes:" + echo " 0 If inside a repository and all checks return normal" + echo " 1 If untracked files detected" + echo " 2 If dirty/modified files detected" + echo " 3 If any ongoing git operation is in progress" + echo " 4 If not inside a git repository" + echo "" + echo " Exit any other value on error or if 'precheck' operation is" + echo " not completed, such as when viewing this help text." + exit 128 +} + +quiet="" +ignore_dirty="" +ignore_untracked="" + +while true; do + case "$1" in + --quiet) quiet="true" ;; + --ignore-dirty) ignore_dirty="true" ;; + --ignore-untracked) ignore_untracked="true" ;; + --help) usage ;; + -h) usage ;; + *) break + esac + shift +done + +if [ $# -ne 0 ]; then + printf 'precheck: Unrecognized option given: %s\n' "$1" + exit 128 +fi + +check() { + if git rev-parse --verify "$1" >/dev/null 2>&1; then + [ -z "$quiet" ] && printf '\e[0;31m%s in progress\e[0m\n' "$2" + exit 3 + fi +} + +if ! [ "$(git rev-parse --is-inside-work-tree 2>/dev/null)" = "true" ]; then + [ -z "$quiet" ] && printf '\e[0;31mNot inside a git work tree\e[0m\n' + exit 4 +fi + +check MERGE_HEAD Merge +check REBASE_HEAD Rebase +check REVERT_HEAD Revert +check CHERRY_PICK_HEAD Cherry-pick +check BISECT_EXPECTED_REV Bisect + +if [ -e "$(git rev-parse --git-path rebase-apply 2>/dev/null)" ]; then + [ -z "$quiet" ] && printf '\e[0;31mrebase-apply (am) found\e[0m\n' + exit 3 +fi + +if [ -z "$ignore_dirty" ]; then + if git status --porcelain 2>/dev/null \ + | grep --quiet --invert-match '^??'; then + [ -z "$quiet" ] && printf '\e[0;31mModified files detected\e[0m\n' + exit 2 + fi +fi + +if [ -z "$ignore_untracked" ]; then + if git status --porcelain 2>/dev/null \ + | grep --quiet '^??'; then + [ -z "$quiet" ] && printf '\e[0;31mUntracked files detected\e[0m\n' + exit 1 + fi +fi + +exit 0 -- cgit v1.2.3 From 2477bb20257689d4d680701934cdb659c8f6fb37 Mon Sep 17 00:00:00 2001 From: Matt Hunter Date: Sat, 21 Feb 2026 17:35:55 -0500 Subject: Use git-precheck to determine if we are inside a repository Use the more robust check implemented by the new git-precheck script, instead of the previous dot_git() logic which checks for a ".git" folder with fallback to git-rev-parse. There is still more work to be done though in refactoring this area of the git-sonar script. Due to the specifics of this new implementation, git-sonar will no longer attempt to operate inside a .git directory or a bare git repository. This makes more sense to me, since git-sonar is intended to be an aid during active development work or branch management from within a working tree. This also avoids some other issues and potential edge cases within the script that fail to run properly in those contexts. git-precheck exits with a code of 3 or less if it successfully determines we are inside a valid git repository working tree, so simply assert this in the is_repo function. Signed-off-by: Matt Hunter --- git-sonar | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/git-sonar b/git-sonar index f957b73..8917cab 100755 --- a/git-sonar +++ b/git-sonar @@ -90,11 +90,8 @@ dot_git() { } is_repo() { - if [[ -n "$(dot_git)" ]]; then - return 0 - else - return 1 - fi + git-precheck --quiet + [ $? -lt 4 ] } record_timestamp() { -- cgit v1.2.3 From 8fc0fa9a8cf84d0d2c7ac5f4e3b4c79fadb99d8c Mon Sep 17 00:00:00 2001 From: Matt Hunter Date: Sun, 22 Feb 2026 02:56:35 -0500 Subject: Add new prompt output element "condition" Use git-precheck to determine if any ongoing git operation is in progress and if so, mark the repository as being in a special condition. This is made visible via a new feature in the GIT_RADAR_FORMAT prompt string '%{condition}', which renders '!' when active. Like most others, this element comes with its own configurable color. By default, this is yellow, which is used for other 'conflicted' or abnormal states. This patch removes the unimpactful variable $output from render_prompt() and replaces its use with $PROMPT_FORMAT - what it was initialized to. Signed-off-by: Matt Hunter --- git-sonar | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/git-sonar b/git-sonar index 8917cab..a610d14 100755 --- a/git-sonar +++ b/git-sonar @@ -49,18 +49,21 @@ prepare_colors() { 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_CONDITION="\x01${GIT_RADAR_COLOR_CONDITION:-"\\033[1;33m"}\x02" + COLOR_STASH="\x01${GIT_RADAR_COLOR_STASH:-"\\033[1;33m"}\x02" COLOR_BRANCH="\x01${GIT_RADAR_COLOR_BRANCH:-"\\033[0m"}\x02" 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%{remote: }%{branch}%{ :local}\\x01\\033[1;30m\\x02)\\x01\\033[0m\\x02%{ :stash}%{ :changes}"}" + PROMPT_FORMAT="${GIT_RADAR_FORMAT:-" \\x01\\033[1;30m\\x02git:(\\x01\\033[0m\\x02%{remote: }%{condition}%{branch}%{ :local}\\x01\\033[1;30m\\x02)\\x01\\033[0m\\x02%{ :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" } @@ -450,8 +453,12 @@ stash_status() { fi } +repo_special_condition() { + git-precheck --quiet --ignore-dirty --ignore-untracked \ + || printf "$COLOR_CONDITION!$RESET_COLOR_CONDITION" +} + render_prompt() { - output="$PROMPT_FORMAT" branch_sed="" remote_sed="" local_sed="" @@ -464,7 +471,15 @@ render_prompt() { sed_pre="%{\(\([^%^{^}]*\)\:\)\{0,1\}" sed_post="\(\:\([^%^{^}]*\)\)\{0,1\}}" - if [[ $output =~ ${if_pre}remote${if_post} ]]; then + if [[ $PROMPT_FORMAT =~ ${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/" + else + condition_sed="s/${sed_pre}condition${sed_post}//" + fi + fi + if [[ $PROMPT_FORMAT =~ ${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/" @@ -505,7 +520,8 @@ render_prompt() { fi fi - printf '%b' "$output" | sed \ + printf '%b' "$PROMPT_FORMAT" | sed \ + -e "$condition_sed" \ -e "$remote_sed" \ -e "$branch_sed" \ -e "$changes_sed" \ -- cgit v1.2.3