git-commit-branch.sh edited
78 lines 1.7 kB view raw
1#!/usr/bin/env bash 2set -euo pipefail 3 4if [ "$#" -lt 2 ]; then 5 echo "Usage: $0 <source-branch> <new-branch> [-m \"commit message\"]" 6 exit 1 7fi 8 9source_branch="$1" 10new_branch="$2" 11shift 2 12 13msg="" 14while [[ $# -gt 0 ]]; do 15 case "$1" in 16 -m|--message) 17 shift 18 msg="$1" 19 shift 20 ;; 21 *) 22 echo "Unknown option: $1" 23 exit 1 24 ;; 25 esac 26done 27 28if [ -z "$msg" ]; then 29 echo "Commit message required (-m)" 30 exit 1 31fi 32 33# check if source branch exists 34if ! git rev-parse --verify "$source_branch" >/dev/null 2>&1; then 35 echo "Source branch '$source_branch' does not exist" 36 exit 1 37fi 38 39# check if new branch already exists 40if git rev-parse --verify "$new_branch" >/dev/null 2>&1; then 41 echo "Branch '$new_branch' already exists" 42 exit 1 43fi 44 45# check for staged changes 46if git diff --cached --quiet; then 47 echo "No staged changes to commit" 48 exit 1 49fi 50 51# 1. save staged diff 52patchfile=$(mktemp) 53git diff --cached > "$patchfile" 54 55# 2. prepare a temporary index rooted at source branch 56idx=$(mktemp) 57GIT_INDEX_FILE="$idx" git read-tree "$source_branch" 58 59# 3. apply the staged diff to that index 60if ! GIT_INDEX_FILE="$idx" git apply --cached --allow-empty "$patchfile"; then 61 echo "Failed to apply staged changes on top of $source_branch" 62 rm -f "$patchfile" "$idx" 63 exit 1 64fi 65 66# 4. create commit from that temporary index 67tree=$(GIT_INDEX_FILE="$idx" git write-tree) 68commit=$(echo "$msg" | GIT_INDEX_FILE="$idx" git commit-tree -p "$source_branch" "$tree") 69 70# 5. create branch pointing at the new commit 71git branch "$new_branch" "$commit" 72 73echo "Created branch '$new_branch' from '$source_branch' at commit $commit" 74rm -f "$patchfile" "$idx" 75 76# 6. remove all the staged changes 77git stash push --staged --quiet 78git stash drop --quiet