Created
June 30, 2025 10:22
-
-
Save patkepa/8a014cf9ee7d935261c27fd9f100b79b to your computer and use it in GitHub Desktop.
Revisions
-
patkepa created this gist
Jun 30, 2025 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,146 @@ #!/bin/bash # Git Submodule Dependency Tree Generator # Usage: ./git-submodule-tree.sh <github-repo-url> set -euo pipefail # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' BLUE='\033[0;34m' YELLOW='\033[1;33m' NC='\033[0m' # No Color # Function to print usage usage() { echo "Usage: $0 <github-repo-url>" echo "Example: $0 https://github.com/user/repo.git" exit 1 } # Check if URL is provided if [ $# -eq 0 ]; then usage fi REPO_URL="$1" TEMP_DIR=$(mktemp -d) VISITED_REPOS=() # Clean up on exit cleanup() { rm -rf "$TEMP_DIR" } trap cleanup EXIT # Function to check if repo was already visited is_visited() { local repo="$1" for visited in "${VISITED_REPOS[@]}"; do if [ "$visited" == "$repo" ]; then return 0 fi done return 1 } # Function to extract repo info from .gitmodules parse_gitmodules() { local gitmodules_file="$1" local indent="$2" if [ ! -f "$gitmodules_file" ]; then return fi # Parse .gitmodules file while IFS= read -r line; do if [[ $line =~ ^\[submodule[[:space:]]+\"(.+)\"\] ]]; then local name="${BASH_REMATCH[1]}" local path="" local url="" local branch="" # Read submodule details while IFS= read -r subline && ! [[ $subline =~ ^\[submodule ]]; do if [[ $subline =~ path[[:space:]]*=[[:space:]]*(.+) ]]; then path="${BASH_REMATCH[1]}" elif [[ $subline =~ url[[:space:]]*=[[:space:]]*(.+) ]]; then url="${BASH_REMATCH[1]}" elif [[ $subline =~ branch[[:space:]]*=[[:space:]]*(.+) ]]; then branch="${BASH_REMATCH[1]}" fi done if [ -n "$url" ]; then # Print submodule info echo -e "${indent}├── ${GREEN}${name}${NC}" echo -e "${indent}│ └── ${BLUE}${url}${NC}" # Check for commit hash or branch if [ -n "$path" ] && [ -d "$(dirname "$gitmodules_file")/$path" ]; then cd "$(dirname "$gitmodules_file")/$path" 2>/dev/null || true local commit=$(git rev-parse HEAD 2>/dev/null || echo "") if [ -n "$commit" ]; then echo -e "${indent}│ └── ${YELLOW}commit: ${commit:0:8}${NC}" fi if [ -n "$branch" ]; then echo -e "${indent}│ └── ${YELLOW}branch: ${branch}${NC}" fi cd - > /dev/null 2>&1 || true fi # Mark as visited VISITED_REPOS+=("$url") # Recursively process submodule if not already visited if ! is_visited "$url"; then process_repo "$url" "${indent}│ " fi fi fi done < "$gitmodules_file" } # Function to process a repository process_repo() { local repo_url="$1" local indent="${2:-}" # Skip if already visited if is_visited "$repo_url"; then return fi # Create temporary directory for this repo local repo_dir=$(mktemp -d -p "$TEMP_DIR") # Clone the repository (shallow clone for speed) echo -e "${indent}${RED}Cloning: ${repo_url}${NC}" >&2 if ! git clone --depth 1 --recurse-submodules "$repo_url" "$repo_dir" 2>/dev/null; then echo -e "${indent}${RED}Failed to clone: ${repo_url}${NC}" >&2 return fi # Process .gitmodules if it exists if [ -f "$repo_dir/.gitmodules" ]; then parse_gitmodules "$repo_dir/.gitmodules" "$indent" fi # Clean up this repo rm -rf "$repo_dir" } # Main execution echo -e "${GREEN}Git Submodule Dependency Tree${NC}" echo -e "${GREEN}==============================${NC}" echo -e "${BLUE}${REPO_URL}${NC}" # Mark main repo as visited VISITED_REPOS+=("$REPO_URL") # Process the main repository process_repo "$REPO_URL" "" echo -e "\n${GREEN}Complete!${NC}"