ChatGPT Claude Codex CLI Cohere Cursor DeepSeek Gemini GitHub Copilot GLM Grok Kimi Llama MiniMax Mistral OpenAI opencode Skill

git-pushing

Safely stage, commit, and push intended git changes with conventional commit messages. Use for ordinary non-release pushes when explicitly asked to push, save work remotely, or share a completed change.

LLM Mart · 0 points · 23 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download sickn33-agentic-awesome-skills-skills_git-pushing-286166a.zip · 4 KB
Part of sickn33/agentic-awesome-skills — 427 skills
This skill couldn't be refreshed from GitHub on the last check — you're seeing the last imported snapshot.

Install

skills CLI npx skills add https://github.com/sickn33/agentic-awesome-skills/tree/main/skills/git-pushing
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install sickn33-agentic-awesome-skills@llmmart
Git git clone https://github.com/sickn33/agentic-awesome-skills.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole sickn33/agentic-awesome-skills collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

Git Push Workflow

Stage only intended changes, create a conventional commit, and push to the remote branch.

When to Use

Automatically activate when the user:

  • Explicitly asks to push changes ("push this", "commit and push")
  • Mentions saving work to remote ("save to github", "push to remote")
  • Completes a feature and wants to share it
  • Says phrases like "let's push this up" or "commit these changes"

Safety Gates

Before staging, inspect git status --short --branch, confirm the intended files, and fetch the upstream branch when a concurrent push is plausible. Do not absorb unrelated dirty files.

Read repository policy before choosing the destination branch. If main or master is protected, or the repository defines a maintainer command such as merge:batch, create or use a topic branch and finish through the required pull-request checks. A user request to “push to main” describes the desired final state; it does not authorize bypassing server-side protection. Never keep retrying a direct push after a protected-branch rejection.

The helper requires an empty live index and a conventional commit message before it stages anything. It locks the live index, builds and validates the commit in an isolated temporary index, rejects -- without paths, and atomically updates the branch only if its parent is unchanged.

The helper honors branch.<name>.pushRemote, remote.pushDefault, and the branch's configured upstream, in that order. For a new branch without those settings, it requires origin and establishes origin/<branch>. It rejects detached HEAD and invalid remote configurations before staging.

Do not use this skill for a maintainer merge batch, canonical synchronization, versioned repository release, tag publication, or a repository with an explicit merge:batch, release:prepare, or release:publish workflow. Use that repository's maintainer/release flow instead; it owns pull-request evidence, protected-branch checks, generated files, tags, and publication verification.

Workflow

Use the helper only after the safety gates pass. Resolve the installed directory that contains this SKILL.md and substitute its absolute path for <skill-directory> below; do not assume the current working directory is the catalog repository. With no paths the helper stages all current changes, so use that form only when every dirty file belongs to the requested commit:

bash "<skill-directory>/scripts/smart_commit.sh"

With custom message:

bash "<skill-directory>/scripts/smart_commit.sh" "feat: add feature"

To stage only named files, pass them after --:

bash "<skill-directory>/scripts/smart_commit.sh" "fix: scope change" -- path/to/file

The helper handles isolated staging, commit creation, and push; it does not replace validation, release tooling, or a rebase required by an advanced upstream branch.

Limitations

  • The helper currently requires Git's files ref backend; it rejects reftable repositories before creating a commit because their refs cannot use the filesystem lock protocol.
  • Use this skill only when the task clearly matches the scope described above.
  • Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
  • Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.
Files (agentic-awesome-skills)
  • scripts
    • smart_commit.sh 7 KB
      #!/bin/bash
      set -euo pipefail
      
      # Always inspect and update the repository's real index. An inherited alternate
      # index could otherwise make the safety check observe different staged content.
      unset GIT_INDEX_FILE
      
      CONVENTIONAL_PATTERN='^(feat|fix|ref|refactor|perf|docs|test|build|ci|chore|style|meta|license|revert)(\([A-Za-z0-9._/-]+\))?(!)?: .+'
      MESSAGE="${1:-chore: update code}"
      shift || true
      
      validate_message() {
        local subject=$1
        if [[ ! "$subject" =~ $CONVENTIONAL_PATTERN ]]; then
          echo "Commit message must use the conventional '<type>(<scope>): <subject>' format." >&2
          exit 1
        fi
      }
      
      validate_message "$MESSAGE"
      
      PATH_MODE=false
      if [[ "${1:-}" == "--" ]]; then
        PATH_MODE=true
        shift
      elif [[ "$#" -gt 0 ]]; then
        echo "Pass selected paths after an explicit -- separator." >&2
        exit 1
      fi
      
      if [[ "$PATH_MODE" == true && "$#" -eq 0 ]]; then
        echo "The -- separator requires at least one path." >&2
        exit 1
      fi
      
      BRANCH=$(git symbolic-ref --quiet --short HEAD) || {
        echo "Refusing to commit from a detached HEAD." >&2
        exit 1
      }
      
      REF_FORMAT=$(git rev-parse --show-ref-format 2>/dev/null || true)
      if [[ -z "$REF_FORMAT" || "$REF_FORMAT" == "--show-ref-format" ]]; then
        REF_FORMAT=$(git config --get extensions.refStorage || true)
        REF_FORMAT=${REF_FORMAT:-files}
      fi
      if [[ "$REF_FORMAT" != files ]]; then
        echo "Refusing to run with ref backend '$REF_FORMAT'; safe branch locking currently requires the files backend." >&2
        exit 1
      fi
      
      PUSH_REMOTE=$(git config --get "branch.$BRANCH.pushRemote" || true)
      if [[ -z "$PUSH_REMOTE" ]]; then
        PUSH_REMOTE=$(git config --get remote.pushDefault || true)
      fi
      FETCH_REMOTE=$(git config --get "branch.$BRANCH.remote" || true)
      MERGE_REF=$(git config --get "branch.$BRANCH.merge" || true)
      if [[ -z "$PUSH_REMOTE" ]]; then
        PUSH_REMOTE=${FETCH_REMOTE:-origin}
      fi
      
      if [[ "$PUSH_REMOTE" == "." ]] || ! git remote get-url --push "$PUSH_REMOTE" >/dev/null 2>&1; then
        echo "Configured push remote '$PUSH_REMOTE' does not exist or is not pushable." >&2
        exit 1
      fi
      
      PUSH_BRANCH=$BRANCH
      if [[ "$PUSH_REMOTE" == "$FETCH_REMOTE" && -n "$MERGE_REF" ]]; then
        if [[ "$MERGE_REF" != refs/heads/* ]]; then
          echo "Configured upstream '$MERGE_REF' is not a pushable branch ref." >&2
          exit 1
        fi
        PUSH_BRANCH=${MERGE_REF#refs/heads/}
      fi
      
      HAS_UPSTREAM=false
      if git rev-parse --verify --quiet '@{upstream}' >/dev/null; then
        HAS_UPSTREAM=true
      fi
      SET_UPSTREAM=false
      if [[ "$HAS_UPSTREAM" == false && "$PUSH_REMOTE" == origin ]]; then
        SET_UPSTREAM=true
      fi
      
      GIT_DIR=$(git rev-parse --absolute-git-dir)
      GIT_COMMON_DIR=$(git rev-parse --path-format=absolute --git-common-dir)
      LIVE_INDEX="$GIT_DIR/index"
      LIVE_INDEX_LOCK="$LIVE_INDEX.lock"
      BRANCH_REF="$GIT_COMMON_DIR/refs/heads/$BRANCH"
      BRANCH_REF_LOCK="$BRANCH_REF.lock"
      TEMP_DIR=$(mktemp -d "${TMPDIR:-/tmp}/smart-commit.XXXXXX")
      TEMP_INDEX="$TEMP_DIR/index"
      MESSAGE_FILE="$TEMP_DIR/COMMIT_EDITMSG"
      LOCK_HELD=false
      BRANCH_LOCK_HELD=false
      
      cleanup() {
        rm -rf "$TEMP_DIR"
        if [[ "$LOCK_HELD" == true ]]; then
          rm -f "$LIVE_INDEX_LOCK"
        fi
        if [[ "$BRANCH_LOCK_HELD" == true ]]; then
          rm -f "$BRANCH_REF_LOCK"
        fi
      }
      trap cleanup EXIT
      
      if ! (set -o noclobber; : > "$LIVE_INDEX_LOCK") 2>/dev/null; then
        echo "The Git index is busy; refusing to race another staging operation." >&2
        exit 1
      fi
      LOCK_HELD=true
      
      if ! git diff --cached --quiet; then
        echo "Refusing to commit because the index already contains staged changes." >&2
        echo "Commit or unstage the existing index, then retry with the intended paths." >&2
        exit 1
      fi
      
      PARENT=$(git rev-parse --verify HEAD)
      if [[ -f "$LIVE_INDEX" ]]; then
        cp "$LIVE_INDEX" "$TEMP_INDEX"
      else
        GIT_INDEX_FILE="$TEMP_INDEX" git read-tree "$PARENT"
      fi
      if [[ "$PATH_MODE" == true ]]; then
        GIT_INDEX_FILE="$TEMP_INDEX" git add -- "$@"
      else
        GIT_INDEX_FILE="$TEMP_INDEX" git add -A
      fi
      
      if GIT_INDEX_FILE="$TEMP_INDEX" git diff --cached --quiet; then
        echo "No changes staged for commit." >&2
        exit 1
      fi
      
      EXPECTED_TREE=$(GIT_INDEX_FILE="$TEMP_INDEX" git write-tree)
      printf '%s\n' "$MESSAGE" > "$MESSAGE_FILE"
      
      GIT_INDEX_FILE="$TEMP_INDEX" git hook run --ignore-missing pre-commit
      if [[ $(GIT_INDEX_FILE="$TEMP_INDEX" git write-tree) != "$EXPECTED_TREE" ]]; then
        echo "Pre-commit hooks changed the isolated index; review those changes before retrying." >&2
        exit 1
      fi
      
      GIT_INDEX_FILE="$TEMP_INDEX" git hook run --ignore-missing prepare-commit-msg -- "$MESSAGE_FILE" message
      GIT_INDEX_FILE="$TEMP_INDEX" git hook run --ignore-missing commit-msg -- "$MESSAGE_FILE"
      if [[ $(GIT_INDEX_FILE="$TEMP_INDEX" git write-tree) != "$EXPECTED_TREE" ]]; then
        echo "Commit hooks changed the isolated index; review those changes before retrying." >&2
        exit 1
      fi
      validate_message "$(head -n 1 "$MESSAGE_FILE")"
      
      if [[ $(git config --bool commit.gpgsign || true) == true ]]; then
        CREATED_COMMIT=$(git commit-tree -S "$EXPECTED_TREE" -p "$PARENT" -F "$MESSAGE_FILE")
      else
        CREATED_COMMIT=$(git commit-tree "$EXPECTED_TREE" -p "$PARENT" -F "$MESSAGE_FILE")
      fi
      
      if ! git update-ref "refs/heads/$BRANCH" "$CREATED_COMMIT" "$PARENT"; then
        echo "The branch changed concurrently; refusing to replace or push it." >&2
        exit 1
      fi
      
      mkdir -p "$(dirname "$BRANCH_REF_LOCK")"
      if ! (set -o noclobber; : > "$BRANCH_REF_LOCK") 2>/dev/null; then
        CURRENT_BRANCH_COMMIT=$(git rev-parse --verify "refs/heads/$BRANCH")
        if [[ "$CURRENT_BRANCH_COMMIT" != "$CREATED_COMMIT" ]]; then
          GIT_INDEX_FILE="$TEMP_INDEX" git read-tree "$CURRENT_BRANCH_COMMIT"
        fi
        cp "$TEMP_INDEX" "$LIVE_INDEX_LOCK"
        mv -f "$LIVE_INDEX_LOCK" "$LIVE_INDEX"
        LOCK_HELD=false
        echo "The branch ref is busy after commit creation; refusing to continue to hooks or push." >&2
        exit 1
      fi
      BRANCH_LOCK_HELD=true
      CURRENT_BRANCH_COMMIT=$(git rev-parse --verify "refs/heads/$BRANCH")
      if [[ "$CURRENT_BRANCH_COMMIT" != "$CREATED_COMMIT" ]]; then
        GIT_INDEX_FILE="$TEMP_INDEX" git read-tree "$CURRENT_BRANCH_COMMIT"
        cp "$TEMP_INDEX" "$LIVE_INDEX_LOCK"
        mv -f "$LIVE_INDEX_LOCK" "$LIVE_INDEX"
        LOCK_HELD=false
        echo "The branch changed before its ref lock was acquired; refusing to push." >&2
        exit 1
      fi
      
      if ! GIT_INDEX_FILE="$TEMP_INDEX" git hook run --ignore-missing post-commit; then
        echo "Warning: post-commit hook failed after the commit was created; continuing with a consistent index." >&2
      fi
      CURRENT_BRANCH_COMMIT=$(git rev-parse --verify "refs/heads/$BRANCH")
      if [[ "$CURRENT_BRANCH_COMMIT" != "$CREATED_COMMIT" ]]; then
        GIT_INDEX_FILE="$TEMP_INDEX" git read-tree "$CURRENT_BRANCH_COMMIT"
        cp "$TEMP_INDEX" "$LIVE_INDEX_LOCK"
        mv -f "$LIVE_INDEX_LOCK" "$LIVE_INDEX"
        LOCK_HELD=false
        echo "The branch changed after commit creation; refusing to push another commit." >&2
        exit 1
      fi
      
      cp "$TEMP_INDEX" "$LIVE_INDEX_LOCK"
      mv -f "$LIVE_INDEX_LOCK" "$LIVE_INDEX"
      LOCK_HELD=false
      
      PUSH_REFSPEC="$CREATED_COMMIT:refs/heads/$PUSH_BRANCH"
      git push "$PUSH_REMOTE" "$PUSH_REFSPEC"
      if [[ "$SET_UPSTREAM" == true ]]; then
        git config "branch.$BRANCH.remote" "$PUSH_REMOTE"
        git config "branch.$BRANCH.merge" "refs/heads/$PUSH_BRANCH"
      fi
      
      rm -f "$BRANCH_REF_LOCK"
      BRANCH_LOCK_HELD=false
      
      echo "✅ Successfully pushed $BRANCH to $PUSH_REMOTE/$PUSH_BRANCH"
      
  • SKILL.md 3.6 KB
    ---
    name: git-pushing
    description: "Safely stage, commit, and push intended git changes with conventional commit messages. Use for ordinary non-release pushes when explicitly asked to push, save work remotely, or share a completed change."
    risk: critical
    source: community
    date_added: "2026-02-27"
    ---
    
    # Git Push Workflow
    
    Stage only intended changes, create a conventional commit, and push to the remote branch.
    
    ## When to Use
    Automatically activate when the user:
    
    - Explicitly asks to push changes ("push this", "commit and push")
    - Mentions saving work to remote ("save to github", "push to remote")
    - Completes a feature and wants to share it
    - Says phrases like "let's push this up" or "commit these changes"
    
    ## Safety Gates
    
    Before staging, inspect `git status --short --branch`, confirm the intended files, and fetch the upstream branch when a concurrent push is plausible. Do not absorb unrelated dirty files.
    
    Read repository policy before choosing the destination branch. If `main` or `master` is protected, or the repository defines a maintainer command such as `merge:batch`, create or use a topic branch and finish through the required pull-request checks. A user request to “push to main” describes the desired final state; it does not authorize bypassing server-side protection. Never keep retrying a direct push after a protected-branch rejection.
    
    The helper requires an empty live index and a conventional commit message before it stages anything. It locks the live index, builds and validates the commit in an isolated temporary index, rejects `--` without paths, and atomically updates the branch only if its parent is unchanged.
    
    The helper honors `branch.<name>.pushRemote`, `remote.pushDefault`, and the branch's configured upstream, in that order. For a new branch without those settings, it requires `origin` and establishes `origin/<branch>`. It rejects detached HEAD and invalid remote configurations before staging.
    
    Do not use this skill for a maintainer merge batch, canonical synchronization, versioned repository release, tag publication, or a repository with an explicit `merge:batch`, `release:prepare`, or `release:publish` workflow. Use that repository's maintainer/release flow instead; it owns pull-request evidence, protected-branch checks, generated files, tags, and publication verification.
    
    ## Workflow
    
    Use the helper only after the safety gates pass. Resolve the installed directory that contains this `SKILL.md` and substitute its absolute path for `<skill-directory>` below; do not assume the current working directory is the catalog repository. With no paths the helper stages all current changes, so use that form only when every dirty file belongs to the requested commit:
    
    ```bash
    bash "<skill-directory>/scripts/smart_commit.sh"
    ```
    
    With custom message:
    
    ```bash
    bash "<skill-directory>/scripts/smart_commit.sh" "feat: add feature"
    ```
    
    To stage only named files, pass them after `--`:
    
    ```bash
    bash "<skill-directory>/scripts/smart_commit.sh" "fix: scope change" -- path/to/file
    ```
    
    The helper handles isolated staging, commit creation, and push; it does not replace validation, release tooling, or a rebase required by an advanced upstream branch.
    
    ## Limitations
    - The helper currently requires Git's `files` ref backend; it rejects `reftable` repositories before creating a commit because their refs cannot use the filesystem lock protocol.
    - Use this skill only when the task clearly matches the scope described above.
    - Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
    - Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related