111 lines · 2.5 KB · Text
RawDownload
#!/usr/bin/env bash set -euo pipefail# Disable glob expansion to handle brackets in file pathsset -fusage() {  printf 'Usage: %s [--force] "commit message" "file" ["file" ...]\n' "$(basename "$0")" >&2  exit 2} if [ "$#" -lt 2 ]; then  usagefi force_delete_lock=falseif [ "${1:-}" = "--force" ]; then  force_delete_lock=true  shiftfi if [ "$#" -lt 2 ]; then  usagefi commit_message=$1shift if [[ "$commit_message" != *[![:space:]]* ]]; then  printf 'Error: commit message must not be empty\n' >&2  exit 1fi if [ -e "$commit_message" ]; then  printf 'Error: first argument looks like a file path ("%s"); provide the commit message first\n' "$commit_message" >&2  exit 1fi if [ "$#" -eq 0 ]; then  usagefi files=("$@") # Disallow "." because it stages the entire repository and defeats the helper's safety guardrails.for file in "${files[@]}"; do  if [ "$file" = "." ]; then    printf 'Error: "." is not allowed; list specific paths instead\n' >&2    exit 1  fidone last_commit_error='' run_git_commit() {  local stderr_log  stderr_log=$(mktemp)  if git commit -m "$commit_message" -- "${files[@]}" 2> >(tee "$stderr_log" >&2); then    rm -f "$stderr_log"    last_commit_error=''    return 0  fi   last_commit_error=$(cat "$stderr_log")  rm -f "$stderr_log"  return 1} for file in "${files[@]}"; do  if [ ! -e "$file" ]; then    # Allow staging deletions: when a file is removed from disk, it may no longer exist in the index    # (once staged for deletion), but it can still exist in HEAD.    if ! git ls-files --error-unmatch -- "$file" >/dev/null 2>&1; then      if ! git cat-file -e "HEAD:$file" >/dev/null 2>&1; then        printf 'Error: file not found: %s\n' "$file" >&2        exit 1      fi    fi  fidone git restore --staged :/git add -A -- "${files[@]}" if git diff --staged --quiet; then  printf 'Warning: no staged changes detected for: %s\n' "${files[*]}" >&2  exit 1fi committed=falseif run_git_commit; then  committed=trueelif [ "$force_delete_lock" = true ]; then  lock_path=$(    printf '%s\n' "$last_commit_error" |      awk -F"'" '/Unable to create .*\.git\/index\.lock/ { print $2; exit }'  )   if [ -n "$lock_path" ] && [ -e "$lock_path" ]; then    rm -f "$lock_path"    printf 'Removed stale git lock: %s\n' "$lock_path" >&2    if run_git_commit; then      committed=true    fi  fifi if [ "$committed" = false ]; then  exit 1fi printf 'Committed "%s" with %d files\n' "$commit_message" "${#files[@]}"