Skip to content

Instantly share code, notes, and snippets.

@sposmen
Last active September 10, 2025 15:24
Show Gist options
  • Save sposmen/2a61e8a11caf058d3acee8fead63693c to your computer and use it in GitHub Desktop.
Save sposmen/2a61e8a11caf058d3acee8fead63693c to your computer and use it in GitHub Desktop.
Github gh command plugin showing prs tree

gh-pr-tree

gh-pr-tree is a GitHub CLI extension that helps you visualize the dependency tree of pull requests.

Normally, gh pr list --base <branch> only shows the direct PRs targeting a branch. With gh-pr-tree, you can see all descendants recursively as a hierarchical tree, making it easier to track stacked PRs and feature branch chains.

Setup

Requirements

  • gh command
  • jq command

Installation

  1. Download gh-pr-tree
  2. Make it executable chmod +x gh-pr-tree
  3. Copy gh-pr-tree into a bin PATH:
    mkdir -p ~/.local/bin
    mv gh-pr-tree ~/.local/bin/
    export PATH="$HOME/.local/bin:$PATH"
  4. To make it permanent add the export to your ~/.bashrc or ~/.zshrc

Usage

gh-pr-tree <base-branch>

Example

gh-pr-tree feature-x

🌱 PR tree starting from base: feature-x
β”œβ”€ PR #12: Initial adjustments (head: feature-y)
β”‚  β”œβ”€ PR #15: Validation fixes (head: feature-z)
β”‚  β”‚  └─ PR #18: Final refactor (head: feature-w)
β”‚  └─ PR #16: Docs update (head: feature-docs)
└─ PR #20: UI improvements (head: feature-ui)
#!/usr/bin/env bash
# Usage: gh-pr-tree <base-branch>
#
# This script prints the PR tree starting from a base branch, including
# the PR of the base branch itself (if it exists).
# Requires: GitHub CLI (gh) and jq
# ANSI colors
RESET="\033[0m"
CYAN="\033[36m"
GREEN="\033[32m"
YELLOW="\033[33m"
GRAY="\033[90m"
BASE="$1"
if [ -z "$BASE" ]; then
echo "❌ You must provide a base branch"
exit 1
fi
VISITED=""
already_visited() {
echo "$VISITED" | grep -q "\b$1\b"
}
mark_visited() {
VISITED="$VISITED $1"
}
print_pr() {
local number="$1"
local title="$2"
local head="$3"
local prefix="$4"
local connector="$5"
echo -e "${prefix}${connector} ${CYAN}PR #$number${RESET}: ${GREEN}$title${RESET} (head: ${YELLOW}$head${RESET})"
}
list_descendants() {
local base_branch="$1"
local prefix="$2"
if already_visited "$base_branch"; then
return
fi
mark_visited "$base_branch"
prs=$(gh pr list --base "$base_branch" --json number,title,headRefName -q '.[]')
if [ -z "$prs" ]; then
return
fi
count=$(echo "$prs" | jq -s 'length')
idx=0
echo "$prs" | jq -c '. | {number, title, headRefName}' | while read -r pr; do
idx=$((idx+1))
number=$(echo "$pr" | jq -r '.number')
title=$(echo "$pr" | jq -r '.title')
head=$(echo "$pr" | jq -r '.headRefName')
if [ "$idx" -eq "$count" ]; then
connector="${GRAY}└─${RESET}"
new_prefix="$prefix "
else
connector="${GRAY}β”œβ”€${RESET}"
new_prefix="$prefix${GRAY}β”‚ ${RESET}"
fi
print_pr "$number" "$title" "$head" "$prefix" "$connector"
list_descendants "$head" "$new_prefix"
done
}
# Try to get PR of the base branch itself
base_pr=$(gh pr list --head "$BASE" --json number,title,headRefName -q '.[0]')
if [ -n "$base_pr" ]; then
number=$(echo "$base_pr" | jq -r '.number')
title=$(echo "$base_pr" | jq -r '.title')
head=$(echo "$base_pr" | jq -r '.headRefName')
print_pr "$number" "$title" "$head" "" ""
else
echo -e "🌱 Starting from base branch: ${YELLOW}$BASE${RESET}"
fi
list_descendants "$BASE" ""
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment