latest commit

This commit is contained in:
2026-02-04 11:06:15 +01:00
commit cbe6428c97
6 changed files with 631 additions and 0 deletions

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 Allan Christensen
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

228
README.md Normal file
View File

@@ -0,0 +1,228 @@
# Bash Git Prompt for Ubuntu 24.04 Server
[![OS](https://img.shields.io/badge/ubuntu-24.04-E95420)](#)
[![Shell](https://img.shields.io/badge/shell-bash-121011)](#)
[![Feature](https://img.shields.io/badge/feature-git_prompt-0078D7)](#)
[![License](https://img.shields.io/badge/License-MIT-green)](./LICENSE)
Install Bash Git Prompt on Ubuntu 24.04 server.
> **Note**
> Safe for production use. This tool only modifies your shell prompt and does not change system services.
---
## Why this installer exists
Most Bash Git prompts out there are bloated. You have to install oh-my-zsh, oh-my-bash, or some other framework that drags in far more than you need.
This project is the opposite: a fast, lightweight Git status prompt based purely on Bash and Git's own built-in commands.
No frameworks, no plugins, no bloat.
---
## What this installer does
- Shows current Git branch and live repo status
- Supports **five clean themes** (including Powerline and two-line layouts) switchable in real time
- Displays staged, changed, untracked, stashed, and remote state
- Indicates clean/dirty status immediately
- Lets you customise PS1 inside/outside Git repos centrally
- Works seamlessly over SSH
- Includes an **optional** Nerd Font installer
---
## What this installer does NOT do
It will not stop you from running the script without reading the documentation like there is no tomorrow.
Skip the README, and whatever happens next is your headache, not a bug report.
---
### Prerequisites
Requires **JetBrainsMono Nerd Font Mono** for proper symbol display like shown below.
<p align="left" width="100%">
<img src="https://git.x-files.dk/assets/bgp-symbols.png" alt="Extended Symbols"/>
</p>
---
### Prompt Structure
The default prompt layout is:
```plaintext
<branch git status><working directory>
```
Example output with the default theme:
<p align="center" width="100%">
<img src="https://git.x-files.dk/assets/bgp-gittheme1.png" alt="Default Theme"/>
</p>
And here the default theme with all the bells and whistles:
<p align="center" width="100%">
<img src="https://git.x-files.dk/assets/bgp-gittheme2.png" alt="Default Theme All Icons"/>
</p>
---
### Installation
Clone the repository:
```
git clone https://git.x-files.dk/bash/bash-git-prompt.git ~/.bash-git-prompt
```
Install fonts:
```
cd ~/.bash-git-prompt
./install-fonts.sh
```
---
## Important note about fonts (SSH users take notice)
The Git prompt uses Nerd Font symbols, but:
**You only need Nerd Fonts installed on your local machine.**
Your terminal emulator on your laptop/workstation renders the symbols, not the server.
If you SSH into the server, the prompt will display correctly as long as your local terminal already has the Nerd Font installed.
If you are installing this on a remote server, you can safely skip the font installer.
---
## Make it happen
Add the following to your .bashrc file:
```
# Git Prompt Start
if [ -f "$HOME/.bash-git-prompt/bash-git-prompt" ]; then
export GIT_PROMPT_THEME=1
source "$HOME/.bash-git-prompt/bash-git-prompt"
fi
# Git Prompt Stop
```
Reload your environment:
```
source ~/.bashrc
```
---
### Switching Themes
Change themes dynamically with:
```
gpchange <theme number>
```
Example:
```
gpchange 3
```
This updates the theme instantly for your current session.
---
### Changing the prompt layout
Prompt layout is handled centrally in the script inside the `update_git_prompt()` function.
Each theme controls its own structure:
- Theme 1, 4, and 5 use a single-line prompt
- Theme 2 uses a Powerline-style segmented prompt
- Theme 3 uses a two-line prompt
If you want to customise the prompt layout, edit the relevant theme block inside `update_git_prompt()`.
This keeps icons, colours, and layout clearly separated and avoids breaking other themes.
---
### Available Themes
Preview of all five themes (clean and dirty as well as ahead and behind shown together for comparison):
Branch -> Staged -> Changed -> Untracked -> Stashed -> Ahead -> Behind -> No-Remote -> Conflict -> Dirty -> Clean
<p align="center" width="100%">
<img src="https://git.x-files.dk/assets/bgp-gittheme3.png" alt="All Themes"/>
</p>
> **Note**
> Theme 1, 2 and 3 require **JetBrainsMono Nerd Font Mono** for proper symbol rendering.
> Theme 4 is purely **Unicode** -- no special fonts are needed for proper symbol rendering.
> Theme 5 is **terminal safe** so no special fonts needed for proper symbol rendering.
---
### Terminal Font Setup
Set your terminal to use:
```
JetBrainsMono Nerd Font Mono
```
<p align="center" width="100%">
<img src="https://git.x-files.dk/assets/bgp-gittheme4.png" alt="Terminal Font Settings"/>
</p>
---
### Troubleshooting
**Symbols not showing correctly:**
Make sure your terminal uses *JetBrainsMono Nerd Font Mono*.
Restart your terminal after installing fonts.
Log out and back in after installing fonts.
**Prompt not loading:**
Verify these lines exist and are correct in `~/.bashrc`:
```
# Git Prompt Start
if [ -f "$HOME/.bash-git-prompt/bash-git-prompt" ]; then
export GIT_PROMPT_THEME=1
source "$HOME/.bash-git-prompt/bash-git-prompt"
fi
# Git Prompt Stop
```
---
### FAQ
**Q:** Does this replace my default prompt entirely?
**A:** No. The Git-aware segment only appears when your current directory is inside a Git repository.
**Q:** Can I create my own theme?
**A:** Absolutely. Each theme is defined in the script under `set_git_prompt_theme_icons()`.
You can modify or extend it, then set your new theme using `export GIT_PROMPT_THEME=<number>`.
**Q:** Does it slow down Git-heavy directories?
**A:** Negligibly. The script uses optimized Git calls and caches status checks for performance.
---
### More Information
More guides and documentation can be found on [wiki.x-files.dk](https://wiki.x-files.dk)
---
### License
Licensed under the [MIT License](./LICENSE).

367
bash-git-prompt Normal file
View File

@@ -0,0 +1,367 @@
# Author : Allan Christensen
# First Created : 24-06-2025 (DD-MM-YYYY)
# Description : Bash Git prompt for Linux
# License : MIT License
#
# Set default theme to 1 if it's not already set
#
GIT_PROMPT_THEME="${GIT_PROMPT_THEME:-1}"
#
# ANSI-safe base colors (cursor safe)
#
C_USER='\[\e[0;32m\]'
C_PATH='\[\e[38;5;178m\]'
C_RESET='\[\e[0m\]'
#
# Default git reset (theme-aware override below)
#
C_GIT_RESET="$C_RESET"
#
# Powerline glyph only 1 specific glyph is needed.
#
PL_SEP=""
# Icons define *symbols only* — no colors or layout here
#
# Theme icon definitions
#
set_git_prompt_theme_icons() {
case "$GIT_PROMPT_THEME" in
1)
# Theme 1: Default icons (requires Nerd Font)
BRANCH_ICON=" "
STAGED_ICON=""
CONFLICT_ICON="≠"
CHANGED_ICON="±"
UNTRACKED_ICON="…"
STASHED_ICON=""
AHEAD_ICON=""
BEHIND_ICON=""
NO_REMOTE_ICON="󰊠"
CLEAN_ICON="✔"
DIRTY_ICON="✘"
;;
2)
# Theme 2: Powerline icons (requires Nerd Font)
BRANCH_ICON=" "
STAGED_ICON=""
CONFLICT_ICON="≠"
CHANGED_ICON="±"
UNTRACKED_ICON="…"
STASHED_ICON=""
AHEAD_ICON=""
BEHIND_ICON=""
NO_REMOTE_ICON="󰊠"
CLEAN_ICON="✔"
DIRTY_ICON="✘"
;;
3)
# Theme 3: Two-liner icons (requires Nerd Font)
BRANCH_ICON=" "
STAGED_ICON=""
CONFLICT_ICON="≠"
CHANGED_ICON="±"
UNTRACKED_ICON="…"
STASHED_ICON=""
AHEAD_ICON=""
BEHIND_ICON=""
NO_REMOTE_ICON="󰊠"
CLEAN_ICON="✔"
DIRTY_ICON="✘"
;;
4)
# Theme 4: ANSI / Unicode-safe icons no special font needed
BRANCH_ICON="⎇ "
STAGED_ICON="o"
CONFLICT_ICON="!"
CHANGED_ICON="±"
UNTRACKED_ICON="…"
STASHED_ICON="☰"
AHEAD_ICON="⇡"
BEHIND_ICON="⇣"
NO_REMOTE_ICON="-"
CLEAN_ICON="✓"
DIRTY_ICON="✗"
;;
5)
# Theme 5: Terminal-safe (ASCII) icons no special font needed
BRANCH_ICON=":: "
STAGED_ICON="+"
CONFLICT_ICON="x"
CHANGED_ICON="*"
UNTRACKED_ICON="?"
STASHED_ICON="s"
AHEAD_ICON="a"
BEHIND_ICON="b"
NO_REMOTE_ICON="no"
CLEAN_ICON="ok"
DIRTY_ICON="!"
;;
esac
}
# Colors define *foreground/background* — layout happens later
#
# Theme-aware git colors
#
set_git_prompt_theme_colors() {
case "$GIT_PROMPT_THEME" in
1)
# Theme 1: Default colors
GC_BRANCH='\[\e[38;5;117m\]'
GC_STAGED='\[\e[38;5;196m\]'
GC_CONFLICT='\[\e[38;5;196m\]'
GC_CHANGED='\[\e[38;5;69m\]'
GC_UNTRACKED='\[\e[38;5;41m\]'
GC_STASHED='\[\e[38;5;226m\]'
GC_AHEAD='\[\e[0;37m\]'
GC_BEHIND='\[\e[0;37m\]'
GC_NOREMOTE='\[\e[38;5;250m\]'
GC_CLEAN='\[\e[0;32m\]'
GC_DIRTY='\[\e[38;5;196m\]'
C_GIT_RESET="$C_RESET"
;;
2)
# Theme 2: Powerline colors
PL_GIT_BG='\[\e[44m\]'
PL_GIT_FG='\[\e[97m\]'
PL_GIT_SEP='\[\e[30;44m\]'
PL_PATH_BG='\[\e[107m\]'
PL_PATH_FG='\[\e[30m\]'
PL_PATH_SEP='\[\e[34;107m\]'
PL_END_SEP='\[\e[97;49m\]'
GC_BRANCH='\[\e[97m\]'
GC_STAGED='\[\e[97m\]'
GC_CONFLICT='\[\e[97m\]'
GC_CHANGED='\[\e[97m\]'
GC_UNTRACKED='\[\e[97m\]'
GC_STASHED='\[\e[97m\]'
GC_AHEAD='\[\e[97m\]'
GC_BEHIND='\[\e[97m\]'
GC_NOREMOTE='\[\e[97m\]'
GC_CLEAN='\[\e[97m\]'
GC_DIRTY='\[\e[97m\]'
C_GIT_RESET="${PL_GIT_BG}${PL_GIT_FG}"
;;
3)
# Theme 3: Two-liner colors
GC_BRANCH='\[\e[38;5;117m\]'
GC_STAGED='\[\e[38;5;196m\]'
GC_CONFLICT='\[\e[38;5;196m\]'
GC_CHANGED='\[\e[38;5;69m\]'
GC_UNTRACKED='\[\e[38;5;41m\]'
GC_STASHED='\[\e[38;5;226m\]'
GC_AHEAD='\[\e[0;37m\]'
GC_BEHIND='\[\e[0;37m\]'
GC_NOREMOTE='\[\e[38;5;250m\]'
GC_CLEAN='\[\e[0;32m\]'
GC_DIRTY='\[\e[38;5;196m\]'
C_GIT_RESET="$C_RESET"
;;
4)
# Theme 4: ANSI / Unicode-safe colors
GC_BRANCH='\[\e[0;37m\]'
GC_STAGED='\[\e[0;31m\]'
GC_CONFLICT='\[\e[0;31m\]'
GC_CHANGED='\[\e[0;33m\]'
GC_UNTRACKED='\[\e[0;32m\]'
GC_STASHED='\[\e[0;36m\]'
GC_AHEAD='\[\e[0;37m\]'
GC_BEHIND='\[\e[0;37m\]'
GC_NOREMOTE='\[\e[0;37m\]'
GC_CLEAN='\[\e[0;32m\]'
GC_DIRTY='\[\e[0;31m\]'
C_GIT_RESET="$C_RESET"
;;
5)
# Theme 5: Terminal-safe (ASCII) colors
GC_BRANCH='\[\e[0;37m\]'
GC_STAGED='\[\e[0;31m\]'
GC_CONFLICT='\[\e[0;31m\]'
GC_CHANGED='\[\e[0;33m\]'
GC_UNTRACKED='\[\e[0;32m\]'
GC_STASHED='\[\e[0;36m\]'
GC_AHEAD='\[\e[0;37m\]'
GC_BEHIND='\[\e[0;37m\]'
GC_NOREMOTE='\[\e[0;37m\]'
GC_CLEAN='\[\e[0;32m\]'
GC_DIRTY='\[\e[0;31m\]'
C_GIT_RESET="$C_RESET"
;;
esac
}
set_git_prompt_theme_icons
set_git_prompt_theme_colors
#
# Cache (per shell tree)
#
GIT_CACHE_FILE="/dev/shm/git_prompt_${USER}_${PPID}.cache"
#
# State collection
#
git_collect_state() {
GIT_STATE_HEAD=$(git rev-parse HEAD 2>/dev/null) || return 1
GIT_STATE_STATUS=$(git status --porcelain=v1 --branch 2>/dev/null) || return 1
GIT_STATE_STASH_LIST=$(git stash list 2>/dev/null || true)
local untracked_raw
untracked_raw=$(git ls-files --others --exclude-standard 2>/dev/null || true)
GIT_STATE_UNTRACKED=""
while IFS= read -r f; do
for d in node_modules vendor dist build cache uploads public/uploads tmp .terraform .cache; do
[[ "$f" == "$d/"* ]] && continue 2
done
GIT_STATE_UNTRACKED+="$f"$'\n'
done <<< "$untracked_raw"
GIT_STATE_FINGERPRINT=$(printf '%s%s%s%s%s' \
"$GIT_STATE_HEAD" \
"$GIT_STATE_STATUS" \
"$GIT_STATE_STASH_LIST" \
"$GIT_STATE_UNTRACKED" \
"$GIT_PROMPT_THEME" | cksum | awk '{print $1}')
}
#
# Render logic
#
actual_git_prompt_info_logic() {
local branch
branch=$(git symbolic-ref --short HEAD 2>/dev/null || echo "(detached)")
local staged conflicts changed untracked stashed
staged=$(grep -cE '^[AMDR] ' <<<"$GIT_STATE_STATUS")
conflicts=$(grep -cE '^UU ' <<<"$GIT_STATE_STATUS")
changed=$(grep -cE '^.[MD] ' <<<"$GIT_STATE_STATUS")
untracked=$(grep -c . <<<"$GIT_STATE_UNTRACKED")
stashed=$(grep -c . <<<"$GIT_STATE_STASH_LIST")
local first_line=${GIT_STATE_STATUS%%$'\n'*}
local ahead=0 behind=0 has_remote=0
[[ "$first_line" == *"..."* ]] && has_remote=1
[[ "$first_line" =~ ahead\ ([0-9]+) ]] && ahead=${BASH_REMATCH[1]}
[[ "$first_line" =~ behind\ ([0-9]+) ]] && behind=${BASH_REMATCH[1]}
local p=""
p+="${GC_BRANCH}${BRANCH_ICON}${branch}${C_GIT_RESET}"
((staged > 0)) && p+=" ${GC_STAGED}${STAGED_ICON}${staged}${C_GIT_RESET}"
((conflicts > 0)) && p+=" ${GC_CONFLICT}${CONFLICT_ICON}${conflicts}${C_GIT_RESET}"
((changed > 0)) && p+=" ${GC_CHANGED}${CHANGED_ICON}${changed}${C_GIT_RESET}"
((untracked > 0)) && p+=" ${GC_UNTRACKED}${UNTRACKED_ICON}${untracked}${C_GIT_RESET}"
((stashed > 0)) && p+=" ${GC_STASHED}${STASHED_ICON}${stashed}${C_GIT_RESET}"
((ahead > 0)) && p+=" ${GC_AHEAD}${AHEAD_ICON}${ahead}${C_GIT_RESET}"
((behind > 0)) && p+=" ${GC_BEHIND}${BEHIND_ICON}${behind}${C_GIT_RESET}"
((has_remote == 0)) && p+=" ${GC_NOREMOTE}${NO_REMOTE_ICON}${C_GIT_RESET}"
if (( staged + conflicts + changed + untracked == 0 )); then
p+=" ${GC_CLEAN}${CLEAN_ICON}${C_GIT_RESET}"
else
p+=" ${GC_DIRTY}${DIRTY_ICON}${C_GIT_RESET}"
fi
echo "$p"
}
#
# Prompt logic (cache-safe)
#
git_prompt_info() {
git_collect_state || return
if [[ -f "$GIT_CACHE_FILE" ]]; then
local cached_fp
read -r cached_fp < "$GIT_CACHE_FILE"
if [[ "$cached_fp" == "$GIT_STATE_FINGERPRINT" ]]; then
sed '1d' "$GIT_CACHE_FILE"
return
fi
fi
local output
output=$(actual_git_prompt_info_logic)
{
echo "$GIT_STATE_FINGERPRINT"
echo "$output"
} > "$GIT_CACHE_FILE"
echo "$output"
}
#
# Update prompt (readability-ordered)
#
update_git_prompt() {
local PROMPT_CHAR='$'
[[ $EUID -eq 0 ]] && PROMPT_CHAR='#'
local GIT_PS1
GIT_PS1=$(git_prompt_info)
#
# Theme 2: Powerline
#
if [[ "$GIT_PROMPT_THEME" -eq 2 ]]; then
if [[ -n "$GIT_PS1" ]]; then
PS1="${PL_GIT_SEP}${PL_SEP}${PL_GIT_BG}${PL_GIT_FG} ${GIT_PS1} ${PL_PATH_SEP}${PL_SEP}${PL_PATH_BG}${PL_PATH_FG} \w ${PL_END_SEP}${PL_SEP}${C_RESET} ${PROMPT_CHAR} "
else
PS1="${PL_PATH_SEP}${PL_SEP}${PL_PATH_BG}${PL_PATH_FG} \w ${PL_END_SEP}${PL_SEP}${C_RESET} ${PROMPT_CHAR} "
fi
#
# Theme 3: Two-liner
#
elif [[ "$GIT_PROMPT_THEME" -eq 3 ]]; then
if [[ -n "$GIT_PS1" ]]; then
PS1="┌─ ${C_USER}\u@\h${C_RESET} [${GIT_PS1}] ${C_PATH}\w${C_RESET}\n└─ ${PROMPT_CHAR} "
else
PS1="┌─ ${C_USER}\u@\h${C_RESET} ${C_PATH}\w${C_RESET}\n└─ ${PROMPT_CHAR} "
fi
#
# Themes 1, 4, 5: Default single-line
#
else
if [[ -n "$GIT_PS1" ]]; then
PS1="${C_USER}\u@\h${C_RESET} [${GIT_PS1}] ${C_PATH}\w${C_RESET} ${PROMPT_CHAR} "
else
PS1="${C_USER}\u@\h${C_RESET} ${C_PATH}\w${C_RESET} ${PROMPT_CHAR} "
fi
fi
}
PROMPT_COMMAND=update_git_prompt
#
# Theme switcher
#
gpchange() {
local theme="$1"
if [[ "$theme" =~ ^[1-5]$ ]]; then
export GIT_PROMPT_THEME="$theme"
set_git_prompt_theme_icons
set_git_prompt_theme_colors
update_git_prompt
echo "Switched to Git prompt theme $theme"
else
echo "Usage: gpchange <1-5>"
fi
}
#
# End of script
#

Binary file not shown.

9
install-fonts.sh Executable file
View File

@@ -0,0 +1,9 @@
#!/bin/bash
##################################################################################
# First Created: 03012025 Author: Allan Desc: Installs fonts for bash-git-prompt #
##################################################################################
mkdir -p $HOME/.local/share/fonts
cp $HOME/.bash-git-prompt/fonts/*.ttf $HOME/.local/share/fonts
fc-cache -f

6
last-tested Normal file
View File

@@ -0,0 +1,6 @@
------------------------------------
Last tested: 04-02-2026 (DD-MM-YYYY)
Environment: Ubuntu Server 24.04 LTS
Environment: Ubuntu Desktop 24.04 LTS
Environment: Fedora Desktop 43
------------------------------------