| name | git-push |
| description | Safely commit and push changes. Audits .gitignore for sensitive files, stages with git add ., writes a conventional commit (what + why), creates a GitHub repo via gh if none exists, and pushes. Use when the user says "push", "ship it", "commit and push", or invokes /git-push. |
git-push
Safely commit and push the current changes. Every run follows this exact sequence:
1. Safety check
Run git status to see what will be staged. Review the actual file list for:
- Secrets —
.env, .pem, .key, credentials, tokens, API keys
- Internal data — data dumps, migration exports, board exports, JSON/CSV with names/tasks/internal info, database exports. Any folder that looks like a one-off dump (e.g.
*-migration/, *-export/, *-dump/) is a red flag.
- Large binaries — blobs, images, compiled files that don't belong in git
- Files that should be gitignored — check if the repo is public, and whether the file contains anything that shouldn't be on GitHub
- Local filesystem paths — grep staged text files (README, docs, configs, examples) for absolute local paths:
C:\Users\..., C:/Francisco/..., /Users/<name>/..., /home/<name>/..., /mnt/c/..., ~/<name>/.... These leak the author's machine layout and username. Also watch for hardcoded local hostnames, LAN IPs (192.168.*, 10.*), and localhost:<port> references that only make sense on the author's box.
Local paths are a fixable cosmetic leak, not a blocker. When you find one:
- Replace it with a generic placeholder (
/path/to/repo, <repo-root>, ~/projects/<repo>) or a repo-relative path.
- If the path is inside an example command, keep the command runnable — use a clearly-placeholder token like
<your-username> so readers know to substitute.
- Re-stage the edited file before committing. Do NOT ask the user for permission to scrub a local path — just fix it and mention it in the heads-up.
Only stop if you find a real problem (secrets, dumps, binaries). Do NOT theorize about what .gitignore could be missing — check the actual files. If every file in the diff is safe, move on silently.
2. Initialize git if missing
If .git/ does not exist, run git init and continue. If it exists, skip.
3. Stage everything
git add .
4. Write the commit message
Use conventional commits. No co-authoring.
Every message MUST answer both what changed and why it changed.
feat: for new functionality
fix: for bug fixes
chore: for everything else
Bad: feat: add repo mapping — missing the why.
Good: feat: add repo mapping to centralize project navigation
Bad: fix: update query logic — what query? why?
Good: fix: deduplicate subsidiary query to avoid double-counting schedules
Bad: chore: update dependencies — why now?
Good: chore: bump django to 4.2.9 to patch CVE-2024-XXXXX
Before writing the message, inspect both:
- the staged diff
- the current chat context / recent user requests
Check whether the staged work represents one logical change or multiple logical changes bundled together because everything was staged with git add ..
If the diff includes multiple distinct tasks or features, the commit message must say so explicitly instead of pretending everything is one small change. In that case:
- write a multi-line conventional commit message
- use one
type: line per logical change
- make each line include both what changed and why
- order the lines by importance, with the main user-facing change first
Bad multi-change message:
feat: update spotify playback
Good multi-change message:
feat: return playlist context in spotify playback responses to show what started playing feat: add Droid MCP and skill deployment guidance to document the new local setup
Another good multi-change message:
feat: deploy personal skills to Droid to keep Claude and Droid installs in sync docs: update skill guidelines to point at deploy_skills.py and Droid skill folders
Do NOT invent a fake single-feature message when the diff clearly contains unrelated or semi-related work. The message should reflect the true scope of the commit.
Read the diff to understand the changes, then write the message. Use a HEREDOC:
git commit -m "$(cat <<'EOF'
type: what changed and why
EOF
)"
If there is nothing to commit yet (empty repo), create an initial commit after staging so step 5's gh repo create --push has something to push.
5. Ensure a GitHub remote exists
Run git remote -v. Three cases:
a) A remote is already set → skip to step 6.
b) No remote at all → create one on GitHub using gh:
-
Verify auth: gh auth status. If not logged in, stop and ask the user to run gh auth login.
-
Pick a repo name. Default: the current directory's basename. Confirm with the user before creating.
-
Default to private unless the user explicitly says public. Creating a public repo without asking is a mistake — code can contain secrets, half-finished work, or internal context the user didn't mean to publish.
-
Create and push in one call:
gh repo create <name> --source=. --private --push
This creates the GitHub repo, wires up origin, and pushes the current branch with upstream tracking. Do not run git push again afterward.
c) Remote exists but the current branch has no upstream → push with -u:
git push -u origin <current-branch>
6. Push
If step 5 already pushed (cases b and c), skip this step. Otherwise:
git push
Read the push output. If GitHub has renamed or transferred the repo, it prints something like:
remote: This repository moved. Please use the new location:
remote: https://github.com/<org>/<new-name>.git
The push still succeeds via redirect, but the local origin still points at the old name. When you see this notice, update the URL on the spot:
git remote set-url origin https://github.com/<org>/<new-name>.git
Use the exact URL printed after "new location:". Tell the user you updated the origin URL and show the new value.
Rules
- NEVER skip any step.
- NEVER push if the audit flagged something — resolve it first.
- NEVER add a Co-Authored-By line.
- NEVER create a public repo without explicit user consent. Default to private.
- NEVER guess the repo name — confirm with the user before
gh repo create.
- If there are no changes to commit and the remote is already up to date, say so and stop.
- If a pre-commit hook fails, fix the issue and create a NEW commit (don't amend).