#!/usr/bin/env sh # # 这个脚本用于一键提交并推送当前 Git 仓库。 # # 使用命令案例: # sh push-git.sh "提交说明" # chmod +x push-git.sh && ./push-git.sh "提交说明" # ./push-git.sh -m "提交说明" --pull-rebase # ./push-git.sh -m "提交说明" --dry-run # # 这个脚本做的事情: # 1. 自动进入脚本所在 Git 仓库根目录,并检查当前分支和远程仓库。 # 2. 如果存在本地改动,执行 git add -A 和 git commit -m "提交说明"。 # 3. 按当前分支推送到远程仓库;首次推送会自动设置 upstream。 set -eu SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)" REMOTE="origin" MESSAGE="" PULL_REBASE=0 NO_VERIFY=0 DRY_RUN=0 usage() { cat <<'EOF' Usage: ./push-git.sh "commit message" ./push-git.sh -m "commit message" [--pull-rebase] [--dry-run] Options: -m, --message MESSAGE Commit message. -r, --remote REMOTE Git remote name. Default: origin. --pull-rebase Run git pull --rebase before pushing. --no-verify Skip git commit hooks. --dry-run Print commands without running them. -h, --help Show this help. EOF } die() { echo "Error: $*" >&2 exit 1 } run() { echo "git $*" if [ "$DRY_RUN" -eq 1 ]; then return 0 fi git "$@" } while [ "$#" -gt 0 ]; do case "$1" in -m|--message) [ "$#" -ge 2 ] || die "$1 requires a value" MESSAGE="$2" shift 2 ;; -r|--remote) [ "$#" -ge 2 ] || die "$1 requires a value" REMOTE="$2" shift 2 ;; --pull-rebase) PULL_REBASE=1 shift ;; --no-verify) NO_VERIFY=1 shift ;; --dry-run) DRY_RUN=1 shift ;; -h|--help) usage exit 0 ;; --) shift break ;; -*) die "unknown option: $1" ;; *) if [ -z "$MESSAGE" ]; then MESSAGE="$1" else MESSAGE="$MESSAGE $1" fi shift ;; esac done REPO_ROOT="$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel)" cd "$REPO_ROOT" BRANCH="$(git rev-parse --abbrev-ref HEAD)" [ -n "$BRANCH" ] && [ "$BRANCH" != "HEAD" ] || die "detached HEAD detected; checkout a branch before pushing" git remote get-url "$REMOTE" >/dev/null || die "remote not found: $REMOTE" STATUS="$(git status --porcelain)" if [ -n "$STATUS" ]; then if [ -z "$MESSAGE" ]; then if [ "$DRY_RUN" -eq 1 ]; then MESSAGE="" else printf "Commit message: " IFS= read -r MESSAGE fi fi [ -n "$MESSAGE" ] || die "commit message is required when there are local changes" run add -A if [ "$NO_VERIFY" -eq 1 ]; then run commit -m "$MESSAGE" --no-verify else run commit -m "$MESSAGE" fi else echo "No local file changes to commit." fi if [ "$PULL_REBASE" -eq 1 ]; then run fetch "$REMOTE" run pull --rebase "$REMOTE" "$BRANCH" fi if git rev-parse --abbrev-ref --symbolic-full-name '@{u}' >/dev/null 2>&1; then run push "$REMOTE" "$BRANCH" else run push -u "$REMOTE" "$BRANCH" fi