latest commit

This commit is contained in:
2026-02-07 15:57:25 +01:00
commit 75397bc471
6 changed files with 674 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.

263
README.md Normal file
View File

@@ -0,0 +1,263 @@
# 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
```
## 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.
### 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>
---
## 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.
---
### 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.
---
### Customizing the prompt outside Git repositories
When this script is loaded, it manages the shell prompt (`PS1`) dynamically so it can switch between Git and non-Git directories.
As long as the script is loaded, **it owns PS1**.
Any manual `PS1` settings in `.bashrc` will normally have no visible effect, because the prompt is rebuilt automatically. Nothing breaks — the Git prompt simply takes precedence.
If you want to change how the prompt looks **outside Git repositories**, adjust the variables in the script shown below.
#### Outside Git repository prompt colors
These variables control the colors used when you are not inside a Git repository:
```
C_USER_PS1_COLOR='\[\e[0;32m\]'
C_ROOT_PS1_COLOR='\[\e[0;31m\]'
C_PATH_COLOR='\[\e[38;5;178m\]'
C_RESET='\[\e[0m\]'
```
#### Outside Git repository prompt structure
These variables define the prompt layout outside Git repositories:
```
PS1_OUTSIDE_USER="${C_USER_PS1_COLOR}\u@\h${C_RESET} ${C_PATH_COLOR}\w${C_RESET} \$ "
PS1_OUTSIDE_ROOT="${C_ROOT_PS1_COLOR}\u@\h${C_RESET} ${C_PATH_COLOR}\w${C_RESET} # "
```
You can safely modify:
- Colors
- Username and hostname display
- Path formatting
- Prompt character
The Git prompt behavior will continue to work normally.
---
### 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:** While loaded, the script manages PS1 so it can switch automatically between Git and non-Git directories. Outside repositories a simplified prompt is shown; inside repositories the Git-aware prompt is shown.
**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).

375
bash-git-prompt Normal file
View File

@@ -0,0 +1,375 @@
# 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}"
#
# Outside Git prompt configuration
# Purpose: privilege awareness (NOT git state)
# These apply ONLY when this script is sourced
#
#
# ANSI-safe colors for OUTSIDE Git prompts
#
C_USER_PS1_COLOR='\[\e[0;32m\]'
C_ROOT_PS1_COLOR='\[\e[0;31m\]'
C_PATH_COLOR='\[\e[38;5;178m\]'
C_RESET='\[\e[0m\]'
#
# Outside Git directory prompts
#
PS1_OUTSIDE_USER="${C_USER_PS1_COLOR}\u@\h${C_RESET} ${C_PATH_COLOR}\w${C_RESET} \$ "
PS1_OUTSIDE_ROOT="${C_ROOT_PS1_COLOR}\u@\h${C_RESET} ${C_PATH_COLOR}\w${C_RESET} # "
#
# ANSI-safe base colors for GIT prompts only
#
C_USER='\[\e[0;32m\]'
C_PATH='\[\e[38;5;178m\]'
#
# Default git reset (theme-aware override below)
#
C_GIT_RESET="$C_RESET"
#
# Powerline glyph
#
PL_SEP=""
#
# Theme icon definitions
#
set_git_prompt_theme_icons() {
case "$GIT_PROMPT_THEME" in
1)
BRANCH_ICON=" "
STAGED_ICON=""
CONFLICT_ICON="≠"
CHANGED_ICON="±"
UNTRACKED_ICON="…"
STASHED_ICON=""
AHEAD_ICON=""
BEHIND_ICON=""
NO_REMOTE_ICON="󰊠"
CLEAN_ICON="✔"
DIRTY_ICON="✘"
;;
2)
BRANCH_ICON=" "
STAGED_ICON=""
CONFLICT_ICON="≠"
CHANGED_ICON="±"
UNTRACKED_ICON="…"
STASHED_ICON=""
AHEAD_ICON=""
BEHIND_ICON=""
NO_REMOTE_ICON="󰊠"
CLEAN_ICON="✔"
DIRTY_ICON="✘"
;;
3)
BRANCH_ICON=" "
STAGED_ICON=""
CONFLICT_ICON="≠"
CHANGED_ICON="±"
UNTRACKED_ICON="…"
STASHED_ICON=""
AHEAD_ICON=""
BEHIND_ICON=""
NO_REMOTE_ICON="󰊠"
CLEAN_ICON="✔"
DIRTY_ICON="✘"
;;
4)
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)
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
}
#
# Theme-aware git colors (Git context ONLY)
#
set_git_prompt_theme_colors() {
case "$GIT_PROMPT_THEME" in
1)
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)
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)
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)
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)
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
#
update_git_prompt() {
local PROMPT_CHAR='$'
[[ $EUID -eq 0 ]] && PROMPT_CHAR='#'
local GIT_PS1
GIT_PS1=$(git_prompt_info)
#
# Outside Git repository
#
if [[ -z "$GIT_PS1" ]]; then
if [[ $EUID -eq 0 ]]; then
PS1="$PS1_OUTSIDE_ROOT"
else
PS1="$PS1_OUTSIDE_USER"
fi
return
fi
#
# Theme 2: Powerline
#
if [[ "$GIT_PROMPT_THEME" -eq 2 ]]; 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} "
return
fi
#
# Theme 3: Two-liner
#
if [[ "$GIT_PROMPT_THEME" -eq 3 ]]; then
PS1="┌─ ${C_USER}\u@\h${C_RESET} [${GIT_PS1}] ${C_PATH}\w${C_RESET}\n└─ ${PROMPT_CHAR} "
return
fi
#
# Themes 1, 4, 5
#
PS1="${C_USER}\u@\h${C_RESET} [${GIT_PS1}] ${C_PATH}\w${C_RESET} ${PROMPT_CHAR} "
}
PROMPT_COMMAND='update_git_prompt; printf "\e[0m"'
#
# 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: 07-02-2026 (DD-MM-YYYY)
Environment: Ubuntu Server 24.04 LTS
Environment: Ubuntu Desktop 24.04 LTS
Environment: Fedora Desktop 43
------------------------------------