Skip to content

Instantly share code, notes, and snippets.

@PhilippeCarphin
Last active December 15, 2021 01:34
Show Gist options
  • Save PhilippeCarphin/eff52f2ed7eee924b6b8ff2a955f33ae to your computer and use it in GitHub Desktop.
Save PhilippeCarphin/eff52f2ed7eee924b6b8ff2a955f33ae to your computer and use it in GitHub Desktop.
Example use of git-prompt.sh with some nice features
#!/bin/bash
# Download the official git-prompt.sh with
# wget https://raw.githubusercontent.com/git/git/v$(git --version | awk '{print $3}')/contrib/completion/git-prompt.sh -O ~/.git-prompt.sh
# Gives the __git_ps1 function used in __my_git_ps1
source ~/.git-prompt.sh
GIT_PS1_SHOWUNTRACKEDFILES=true
GIT_PS1_SHOWUPSTREAM=verbose
GIT_PS1_SHOWCOLORHINTS=true
GIT_PS1_SHOWDIRTYSTATE=true
PROMPT_COMMAND=__my_git_ps1
################################################################################
# Calls __git_ps1 which sets PS1
# Uses the 3 argument form which results in something like
# PS1=$1$(printf -- $3 $gitstring)$2
# Note only the 2 and 3 argument forms set PS1.
################################################################################
function __my_git_ps1(){
# save exit code of previous command to use in prompt
previous_exit_code=$?
# Color of the non-git part
c="\[\033[35m\]"
nc="\[\033[0m\]"
ps1_exit_code=$(__ps1_format_exit_code $previous_exit_code)
# Arguments for the 3 arg form of __git_ps1
pre="${ps1_exit_code}${c}\u@\h:$(git_pwd)${nc}"
post="${c} \\\$${nc} "
gitstring_format=" (%s$(__git_time_since_last_commit))"
# This sets PS1 (something like PS1=$1$(printf -- $3 $gitstring)$2)
# the '%s' in gitstring_format gets replaced with $gitstring
# which has all the info produced by __git_ps1
__git_ps1 "${pre}" "${post}" "${gitstring_format}"
}
################################################################################
# Prints $PWD when outside a git repo and a shortened version of PWD when
# inside a git repo.
#
# When in a git repo, strip everything from PWD up to but excluding the
# basename of the directory that is the root of the repo:
#
# Shortens
# /home/phc001/Repositories/gitlab.science.gc.ca/phc001/my-git-repo/a/b/c
# to
# my-git-repo/a/b/c
################################################################################
function git_pwd() {
if [[ $(git rev-parse --is-inside-work-tree 2>/dev/null) == true ]] ; then
local repo_dir=$(git rev-parse --show-toplevel 2>/dev/null)
local outer=$(basename $repo_dir)
local inner=$(git rev-parse --show-prefix 2>/dev/null)
echo "${outer}/${inner}"
else
echo '\w'
fi
}
################################################################################
# Print an exit code supplied as an argument.
# Zero is printed in bold green, anything else is printed in bold red
################################################################################
function __ps1_format_exit_code(){
local previous_exit_code=$1
if [[ $previous_exit_code == 0 ]] ; then
color="\[\033[1;32m\]"
else
color="\[\033[1;31m\]"
fi
printf " ${color}$previous_exit_code\[\033[0m\] "
}
################################################################################
# Print time since last commit in a format based on the length of time
################################################################################
__git_time_since_last_commit() {
# This checks if we are in a repo an that there is a commit
if ! git log -n 1 > /dev/null 2>&1; then
return
fi
# If inside GIT_DIR, we can't do the git diff commands to determine
# wheher or not to show the time. So we would like to CD to the repo
# root to run those git diff commands.
# To get the repo root from inside .git, we assume the GIT_DIR is called
# .git and that '/.git' does not occur somewhere else in the path.
# This is a reasonable assumption
local hackish_toplevel=${PWD%%/\.git*}
# Don't show anything if there are no staged or unstaged changes
if (cd ${hackish_toplevel} && git diff --no-ext-diff --quiet && git diff --no-ext-diff --cached --quiet) ; then
return
fi
last_commit_unix_timestamp=$(git log --pretty=format:'%at' -1 2> /dev/null)
now_unix_timestamp=$(date +%s)
seconds_since_last_commit=$(($now_unix_timestamp - $last_commit_unix_timestamp))
format_seconds $seconds_since_last_commit
}
################################################################################
# Formats a duration in seconds to DD:HH:MM or HH:MM if the number of days is 0.
#
# Because this is used for the time since the last commit, seconds are irrelevant
# and the time is rounded to a whole minute.
################################################################################
format_seconds(){
local seconds=$1
# Totals
local MINUTES=$(($seconds / 60))
local HOURS=$(($seconds /3600))
# Sub-hours and sub-minutes
local seconds_per_day=$((60*60*24))
local DAYS=$(($seconds / $seconds_per_day))
local SUB_HOURS=$(( $HOURS % 24))
local SUB_MINUTES=$(( $MINUTES % 60))
# Display
if [ "$DAYS" -gt 1 ]; then
echo " ${DAYS}d${SUB_HOURS}h${SUB_MINUTES}m"
elif [ "$HOURS" -gt 0 ]; then
echo " ${HOURS}h${SUB_MINUTES}m"
else
echo " ${MINUTES}m"
fi
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment