Skip to content

Instantly share code, notes, and snippets.

@schacon
Created January 13, 2024 18:41
Show Gist options
  • Save schacon/e9e743dee2e92db9a464619b99e94eff to your computer and use it in GitHub Desktop.
Save schacon/e9e743dee2e92db9a464619b99e94eff to your computer and use it in GitHub Desktop.
Better Git Branch output
#!/bin/bash
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
NO_COLOR='\033[0m'
BLUE='\033[0;34m'
YELLOW='\033[0;33m'
NO_COLOR='\033[0m'
width1=5
width2=6
width3=30
width4=20
width5=40
# Function to count commits
count_commits() {
local branch="$1"
local base_branch="$2"
local ahead_behind
ahead_behind=$(git rev-list --left-right --count "$base_branch"..."$branch")
echo "$ahead_behind"
}
# Main script
main_branch=$(git rev-parse HEAD)
printf "${GREEN}%-${width1}s ${RED}%-${width2}s ${BLUE}%-${width3}s ${YELLOW}%-${width4}s ${NO_COLOR}%-${width5}s\n" "Ahead" "Behind" "Branch" "Last Commit" " "
# Separator line for clarity
printf "${GREEN}%-${width1}s ${RED}%-${width2}s ${BLUE}%-${width3}s ${YELLOW}%-${width4}s ${NO_COLOR}%-${width5}s\n" "-----" "------" "------------------------------" "-------------------" " "
format_string="%(objectname:short)@%(refname:short)@%(committerdate:relative)"
IFS=$'\n'
for branchdata in $(git for-each-ref --sort=-authordate --format="$format_string" refs/heads/ --no-merged); do
sha=$(echo "$branchdata" | cut -d '@' -f1)
branch=$(echo "$branchdata" | cut -d '@' -f2)
time=$(echo "$branchdata" | cut -d '@' -f3)
if [ "$branch" != "$main_branch" ]; then
# Get branch description
description=$(git config branch."$branch".description)
# Count commits ahead and behind
ahead_behind=$(count_commits "$sha" "$main_branch")
ahead=$(echo "$ahead_behind" | cut -f2)
behind=$(echo "$ahead_behind" | cut -f1)
# Display branch info
printf "${GREEN}%-${width1}s ${RED}%-${width2}s ${BLUE}%-${width3}s ${YELLOW}%-${width4}s ${NO_COLOR}%-${width5}s\n" $ahead $behind $branch "$time" "$description"
fi
done
@schacon
Copy link
Author

schacon commented Jan 13, 2024

CleanShot 2024-01-13 at 19 42 12@2x

@mikeschinkel
Copy link

Nice!

@vigo
Copy link

vigo commented Jan 15, 2024

koool Thanks Scott!

@VictorGob
Copy link

chef kiss

@danalexilewis
Copy link

wicked

@MTRNord
Copy link

MTRNord commented Feb 12, 2024

Hi :) First of all thanks! Any chance to make it aware for long branch names? Currently it looks like this:

image

Which is a little hard to read due to the longer branch names

@l0b0
Copy link

l0b0 commented Feb 13, 2024

One-liner with similar functionality:

git for-each-ref --color --sort=-committerdate --format=$'%(color:red)%(ahead-behind:HEAD)\t%(color:blue)%(refname:short)\t%(color:yellow)%(committerdate:relative)\t%(color:default)%(describe)' refs/heads/ --no-merged | \
    sed 's/ /\t/' | \
    column --separator=$'\t' --table --table-columns='Ahead,Behind,Branch Name,Last Commit,Description'

@yaswant
Copy link

yaswant commented Feb 19, 2024

One-liner with similar functionality:

git for-each-ref --color --sort=-committerdate --format=$'%(color:red)%(ahead-behind:HEAD)\t%(color:blue)%(refname:short)\t%(color:yellow)%(committerdate:relative)\t%(color:default)%(describe)' refs/heads/ --no-merged | \
    sed 's/ /\t/' | \
    column --separator=$'\t' --table --table-columns='Ahead,Behind,Branch Name,Last Commit,Description'

I think ahead-behind field was added in git 2.41..?

@jlebon
Copy link

jlebon commented Feb 23, 2024

Neat! A while ago I wrote https://github.com/jlebon/git-bstatus in the same vein. Some may find it overkill depending on their needs.

@evilr00t
Copy link

evilr00t commented Mar 4, 2024

One-liner with similar functionality:

git for-each-ref --color --sort=-committerdate --format=$'%(color:red)%(ahead-behind:HEAD)\t%(color:blue)%(refname:short)\t%(color:yellow)%(committerdate:relative)\t%(color:default)%(describe)' refs/heads/ --no-merged | \
    sed 's/ /\t/' | \
    column --separator=$'\t' --table --table-columns='Ahead,Behind,Branch Name,Last Commit,Description'

for macos:

bb = !git for-each-ref --color --sort=-committerdate --format=$'%(color:red)%(ahead-behind:HEAD)\t%(color:blue)%(refname:short)\t%(color:yellow)%(committerdate:relative)\t%(color:default)%(describe)' refs/heads/ --no-merged | sed 's/ /\t/' | column -s=$'\t' -t -c 'Ahead,Behind,Branch Name,Last Commit,Description'

column in macos is BSD (not GNU) and has different argument names.

@adi-g15-ibm
Copy link

Thanks for the amazing script !

One change for anyone not wanting two fatal errors and some more output, when you run it by mistake from a directory which is not git repo:

diff --git a/git-better-branch.sh b/git-better-branch.sh
index 6281256f32d3..47d04496658f 100755
--- a/git-better-branch.sh
+++ b/git-better-branch.sh
@@ -27,6 +27,11 @@ count_commits() {
 # Main script
 main_branch=$(git rev-parse HEAD)
 
+if [ $? -ne 0 ]; then
+    # If 'git rev-parse' failed, probably we are not in a git repo, fail now
+    exit 1
+fi
+
 printf "${GREEN}%-${width1}s ${RED}%-${width2}s ${BLUE}%-${width3}s ${YELLOW}%-${width4}s ${NO_COLOR}%-${width5}s\n" "Ahead" "Behind" "Branch" "Last Commit"  " "
 
 # Separator line for clarity

@Azzam-Alotaibi
Copy link

I might be a bit too late, but none of the above is working out for me. Is it depecrated? or am I dumb
I'm using macos, the solution proposed by @evilr00t for macos doesn't show any output.
the .sh file gives an empty table with no branches. I did git branch -a to make sure I'm in the correct path.
Is there any suggestions?

@osbm
Copy link

osbm commented Jul 23, 2024

@Azzam-Alotaibi Hey, i found out that cloning a repository only checkouts the default branch. This script only shows the branches you have checked out. And this script does not show the default branch.

It uses git for-each-ref command to get all the branches and selects the branches that starts with refs/heads

To checkout all the remote branches at once, run this in bash:

for branch in `git branch -a | grep remotes | grep -v HEAD | grep -v master `; do
   git branch --track ${branch#remotes/origin/} $branch
done

I realized this script only uses local branches so if your branches change remotely this may not show accurate information. I need to test if this is the case.

@HexHummingbird
Copy link

One liner that works with git version 2.34.1 on Linux (bash, zsh), MacOS (bash, zsh), Windows (git bash, powershell inside of Windows Terminal):

git for-each-ref --color --sort=-committerdate --format='%(color: bold magenta)%(align:60,left)%(refname:short)%(color:bold red) %(upstream:track,nobracket)%(end)%(color:nobold yellow)%(align:58,left)%(committerdate:format:%Y-%d-%m %H:%M) (%(committerdate:relative), %(committerdate:format:%A %d))%(end)%(color:green)%(align:24,left)%(authorname)%(end)%(color:green)%(align:64,left)%(contents:lines=1)%(end)' refs/heads/ --count 16

It looks a little different. It shows your current branch too and sorts by most recent commit first:

image

It also prints gone near branch when upstream branch is unknown/gone. On Windows may output strange characters and random guids, in current shell session type powershell/bash again and all should be fine. If you modify it and wonder why alignment seems smaller than numbers say, try piping to | cat -v and you will see ANSI color escape sequences, they count too.

Adjust --count 16 to print more/less branches.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment