Files
2025-11-30 08:45:11 +08:00

251 lines
6.0 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# Git Utility Functions
#
# General utility functions for git operations and formatting.
#
# Author: Claude Code get-git-diff skill
# Version: 1.0.0
set -euo pipefail
#######################################
# Get current branch name
# Outputs:
# Branch name, or "HEAD" if detached
#######################################
get_current_branch() {
local branch
branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "HEAD")
echo "${branch}"
}
#######################################
# Get default branch (main or master)
# Outputs:
# Default branch name, or empty if not found
#######################################
get_default_branch() {
if git rev-parse --verify main >/dev/null 2>&1; then
echo "main"
elif git rev-parse --verify master >/dev/null 2>&1; then
echo "master"
else
echo ""
fi
}
#######################################
# Format diff filename
# Arguments:
# $1 - first commit short hash
# $2 - second commit short hash
# $3 - extension (optional, default: md)
# Outputs:
# Formatted filename like "diff_abc123_def456.md"
#######################################
format_diff_filename() {
local hash1="$1"
local hash2="$2"
local ext="${3:-md}"
echo "diff_${hash1}_${hash2}.${ext}"
}
#######################################
# Get repository root directory
# Outputs:
# Absolute path to repository root
#######################################
get_repo_root() {
git rev-parse --show-toplevel 2>/dev/null
}
#######################################
# Get repository name
# Outputs:
# Name of the repository (directory name)
#######################################
get_repo_name() {
local root
root=$(get_repo_root)
if [[ -n "${root}" ]]; then
basename "${root}"
fi
}
#######################################
# Get remote URL (if available)
# Arguments:
# $1 - remote name (optional, default: origin)
# Outputs:
# Remote URL or empty if not found
#######################################
get_remote_url() {
local remote="${1:-origin}"
git remote get-url "${remote}" 2>/dev/null || echo ""
}
#######################################
# Check if commit is reachable from another
# Arguments:
# $1 - ancestor commit
# $2 - descendant commit
# Returns:
# 0 if reachable, 1 if not
#######################################
is_ancestor() {
local ancestor="$1"
local descendant="$2"
git merge-base --is-ancestor "${ancestor}" "${descendant}" 2>/dev/null
}
#######################################
# Get common ancestor of two commits
# Arguments:
# $1 - first commit
# $2 - second commit
# Outputs:
# Common ancestor commit hash
#######################################
get_common_ancestor() {
local commit1="$1"
local commit2="$2"
git merge-base "${commit1}" "${commit2}" 2>/dev/null
}
#######################################
# Format timestamp
# Arguments:
# $1 - format (optional, default: "%Y-%m-%d %H:%M:%S")
# Outputs:
# Formatted current timestamp
#######################################
format_timestamp() {
local format="${1:-%Y-%m-%d %H:%M:%S}"
date "+${format}"
}
#######################################
# Create directory if it doesn't exist
# Arguments:
# $1 - directory path
# Returns:
# 0 if successful or already exists
#######################################
ensure_directory() {
local dir="$1"
if [[ ! -d "${dir}" ]]; then
mkdir -p "${dir}"
fi
}
#######################################
# Get git config value
# Arguments:
# $1 - config key (e.g., user.name)
# Outputs:
# Config value or empty if not set
#######################################
get_git_config() {
local key="$1"
git config --get "${key}" 2>/dev/null || echo ""
}
#######################################
# Check if working directory is clean
# Returns:
# 0 if clean, 1 if dirty
#######################################
is_working_tree_clean() {
git diff-index --quiet HEAD -- 2>/dev/null
}
#######################################
# Get list of all branches
# Arguments:
# $1 - type: "local", "remote", or "all" (default: local)
# Outputs:
# List of branches, one per line
#######################################
get_branches() {
local type="${1:-local}"
case "${type}" in
local)
git branch --format='%(refname:short)' 2>/dev/null
;;
remote)
git branch -r --format='%(refname:short)' 2>/dev/null
;;
all)
git branch -a --format='%(refname:short)' 2>/dev/null
;;
*)
echo "Error: Invalid branch type: ${type}" >&2
return 1
;;
esac
}
#######################################
# Check if ref exists
# Arguments:
# $1 - ref name (branch, tag, commit)
# Returns:
# 0 if exists, 1 if not
#######################################
ref_exists() {
local ref="$1"
git rev-parse --verify "${ref}" >/dev/null 2>&1
}
# Allow script to be sourced or run directly
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
# Example usage
echo "=== Git Repository Utilities ==="
echo ""
echo "Current branch: $(get_current_branch)"
echo "Default branch: $(get_default_branch)"
echo "Repository root: $(get_repo_root)"
echo "Repository name: $(get_repo_name)"
remote_url=$(get_remote_url)
if [[ -n "${remote_url}" ]]; then
echo "Remote URL (origin): ${remote_url}"
fi
echo ""
echo "Git user name: $(get_git_config user.name)"
echo "Git user email: $(get_git_config user.email)"
echo ""
if is_working_tree_clean; then
echo "Working tree: clean"
else
echo "Working tree: dirty (uncommitted changes)"
fi
echo ""
echo "Example filename: $(format_diff_filename "abc123" "def456")"
echo "Current timestamp: $(format_timestamp)"
echo ""
echo "=== Local Branches ==="
get_branches local | head -5
local_count=$(get_branches local | wc -l)
if [[ ${local_count} -gt 5 ]]; then
echo " ... and $((local_count - 5)) more"
fi
fi