git-safety

SKILL.md

Git Safety

CRITICAL: Some Git operations can permanently lose work. This skill prevents commit loss.

Danger Levels

Level Operations Requires
⛔ CRITICAL push --force to shared branch, reset --hard with unpushed work Full verification + explicit confirmation
🔴 HIGH rebase on shared branches, clean -fd, checkout . Stash check + confirmation
🟠 MEDIUM reset --soft/mixed, stash drop, branch -D Verify branch state + confirm
🟢 LOW commit, push, pull, fetch, branch Standard execution

Pre-Operation Protocol

Before Force Push

**CRITICAL: FORCE PUSH REQUESTED**

**Command:** git push --force origin main

**⚠️ THIS REWRITES SHARED HISTORY**

**Current state:**
- Local branch: main
- Local HEAD: abc1234 "Add new feature"
- Remote HEAD: def5678 "Fix bug in login"

**Commits that will be OVERWRITTEN on remote:**
1. def5678 - "Fix bug in login" (by teammate@company.com, 2 hours ago)
2. ghi9012 - "Update documentation" (by teammate@company.com, 3 hours ago)

**These commits will be LOST if not saved elsewhere:**
- 2 commits by other team members
- Anyone who pulled these will have conflicts

**Safety checks:**
- [ ] Is this your personal branch? NO - this is main ⚠️
- [ ] Have you notified the team? Unknown
- [ ] Are the overwritten commits backed up? Unknown

**Safer alternatives:**
1. `git push --force-with-lease` (fails if remote changed)
2. Create a new branch for your changes
3. Merge instead of rebase
4. Coordinate with team first

**I strongly recommend against force pushing to main.**

If you must proceed, type: "yes, force push to main and overwrite 2 commits"

Before Reset --hard

**CRITICAL: HARD RESET REQUESTED**

**Command:** git reset --hard HEAD~3

**⚠️ THIS DISCARDS CHANGES PERMANENTLY**

**What will be LOST:**

**Commits to be removed (3):**
1. abc1234 - "Work in progress on feature X"
2. def5678 - "Add unit tests"
3. ghi9012 - "Fix styling issues"

**Uncommitted changes that will be LOST:**
- Modified: src/App.tsx (45 lines changed)
- Modified: src/utils/helper.ts (12 lines changed)
- Untracked: src/components/NewFeature.tsx (new file, 156 lines)

**Recovery options after reset:**
- Commits: Can recover via `git reflog` (within 90 days)
- Staged changes: Can recover via `git fsck --lost-found`
- Untracked files: PERMANENTLY LOST ⚠️

**Before reset, I will:**
1. Stash uncommitted changes: `git stash push -m "backup before reset"`
2. Create backup branch: `git branch backup-before-reset`
3. Note reflog position: HEAD is currently at abc1234

Proceed with backup and reset? Type "yes, reset after backup" to confirm.

Before Clean

🔴 **DANGEROUS: GIT CLEAN REQUESTED**

**Command:** git clean -fd

**This will DELETE untracked files and directories:**

| Type | Path | Size |
|------|------|------|
| File | .env.local | 1.2 KB ⚠️ (may contain secrets) |
| File | config.local.json | 0.5 KB |
| Dir | node_modules/ | 234 MB (can be recreated) |
| Dir | uploads/ | 45 MB ⚠️ (user uploaded files) |
| File | notes.txt | 2 KB (your notes) |

**Files that will be PRESERVED (tracked):**
- All committed files
- All files in .gitignore that are tracked

**⚠️ WARNING: These untracked files cannot be recovered after deletion:**
- .env.local (may contain API keys!)
- uploads/ (user data!)
- notes.txt (your work!)

**Safer alternatives:**
```bash
# See what would be deleted (dry run)
git clean -fdn

# Interactive mode (choose what to delete)
git clean -fdi

# Exclude certain patterns
git clean -fd -e "*.local" -e "uploads/"

Type "yes, delete untracked files" to proceed, or use a safer alternative above.


### Before Rebase on Shared Branch

```markdown
🔴 **DANGEROUS: REBASE ON SHARED BRANCH**

**Command:** git rebase main feature-branch

**⚠️ REBASE REWRITES HISTORY**

**Branch state:**
- feature-branch has been pushed: Yes
- feature-branch has other contributors: Checking...
  - You: 5 commits
  - teammate@company.com: 2 commits ⚠️

**If you rebase this branch:**
- All 7 commits will get new SHA hashes
- Your teammate will have to force-reset their local branch
- Any PRs referencing old commits will break
- CI/CD caches may be invalidated

**Safer alternatives:**
1. **Merge instead:** `git merge main` (preserves history)
2. **Rebase only your commits:**
   ```bash
   git rebase --onto main HEAD~5  # Only your 5 commits
  1. Create new branch:
    git checkout -b feature-branch-v2
    git rebase main
    

If you must rebase, notify teammates first and type: "yes, rebase shared branch"


### Before Checkout . (Discard All Changes)

```markdown
🔴 **DANGEROUS: DISCARD ALL CHANGES**

**Command:** git checkout . (or git restore .)

**This will DISCARD all uncommitted changes:**

**Modified files (15):**
| File | Lines Changed |
|------|---------------|
| src/App.tsx | +45, -12 |
| src/components/Header.tsx | +23, -5 |
| src/utils/api.ts | +67, -34 |
| ... and 12 more files |

**Total changes to be discarded:**
- 234 lines added
- 89 lines removed
- 15 files modified

**These changes are NOT committed and will be PERMANENTLY LOST.**

**Safer alternatives:**
```bash
# Stash changes (can be recovered later)
git stash push -m "work in progress"

# Discard specific file only
git checkout -- src/App.tsx

# See changes first
git diff

Type "yes, discard all uncommitted changes" to proceed.


### Before Branch -D (Force Delete)

```markdown
🟠 **WARNING: FORCE DELETE BRANCH**

**Command:** git branch -D feature/experimental

**Branch state:**
- Local branch: feature/experimental
- Commits ahead of main: 8
- Merged to main: No ⚠️
- Has remote tracking: No
- Last commit: 2 days ago

**Commits that may be LOST (not on any other branch):**
1. abc1234 - "Experimental feature WIP"
2. def5678 - "Add database schema"
3. ... and 6 more commits

**Recovery:**
- Can recover via `git reflog` within 90 days
- Cannot recover if git gc runs

**Safer alternatives:**
```bash
# Merge first, then delete
git checkout main
git merge feature/experimental
git branch -d feature/experimental  # -d fails if not merged

# Archive the branch instead
git tag archive/feature-experimental feature/experimental
git branch -D feature/experimental

Type "yes, delete unmerged branch" to proceed.


### Before Stash Drop

```markdown
🟠 **WARNING: DROP STASH**

**Command:** git stash drop stash@{0}

**Stash contents:**
- Created: 2024-01-15 14:30:00 (3 days ago)
- Message: "WIP: payment integration"
- Branch: feature/payments
- Files:
  - src/services/payment.ts (modified)
  - src/types/payment.ts (new file)
  - tests/payment.test.ts (modified)

**Changes in this stash:**
- 156 lines added
- 23 lines removed

**Recovery after drop:**
- Very difficult (requires git fsck --lost-found)
- May not be recoverable after git gc

**Safer alternatives:**
```bash
# Apply stash first, then drop
git stash apply stash@{0}
# ... verify changes look good ...
git stash drop stash@{0}

# List all stashes to make sure dropping the right one
git stash list

Type "yes, drop stash" to proceed.


## Safe Git Workflow

### Before Any Destructive Operation

```bash
# 1. Check current state
git status
git log --oneline -5
git stash list

# 2. Create safety backup
git stash push -m "safety backup $(date +%Y%m%d_%H%M%S)"
git branch backup-$(date +%Y%m%d_%H%M%S)

# 3. Note reflog position
git reflog -1  # Remember this hash!

Recovery Commands

# Recover from reset --hard
git reflog                      # Find the commit before reset
git reset --hard HEAD@{1}       # Go back to that commit

# Recover deleted branch
git reflog                      # Find the branch's last commit
git checkout -b recovered-branch abc1234

# Recover dropped stash
git fsck --lost-found           # Find dangling commits
git show abc1234                # Check if it's your stash
git stash apply abc1234

# Recover from clean
# Unfortunately, untracked files are gone
# Check IDE local history, Time Machine, cloud backups

Protected Branches Configuration

Git Hooks for Safety

# .git/hooks/pre-push
#!/bin/bash

protected_branches=("main" "master" "production" "develop")
current_branch=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,')

for branch in "${protected_branches[@]}"; do
  if [ "$current_branch" = "$branch" ]; then
    if [[ "$@" == *"--force"* ]] || [[ "$@" == *"-f"* ]]; then
      echo "⛔ Force push to $branch is BLOCKED"
      echo "Create a PR instead, or use --force-with-lease"
      exit 1
    fi
  fi
done

exit 0

Git Aliases for Safety

# Add to ~/.gitconfig
[alias]
  # Safe force push
  pushf = push --force-with-lease

  # Reset with backup
  safe-reset = "!f() { git branch backup-$(date +%s) && git reset \"$@\"; }; f"

  # Clean with preview
  safe-clean = clean -fdn

  # Delete branch only if merged
  safe-delete = branch -d

  # Show what would be rebased
  rebase-preview = "!f() { git log --oneline HEAD...$1; }; f"

Best Practices Summary

DO DON'T
Use --force-with-lease Use --force on shared branches
Stash before reset Reset with uncommitted changes
Create backup branches Delete unmerged branches carelessly
Use -d for branch delete Use -D without checking merge status
Run clean -n first (dry run) Run clean -fd blindly
Check git status before operations Assume working directory is clean
Use git reflog for recovery Panic after mistakes
Communicate before rebasing shared branches Rebase and force push silently

Pre-Flight Checklist

Before destructive Git operations:

  • Current branch is correct (git branch)
  • No uncommitted changes OR they're stashed (git status)
  • Backup branch created if needed
  • Not operating on protected/shared branch
  • Understand what will be affected
  • Know how to recover if something goes wrong
  • Team notified if affecting shared branches
Weekly Installs
3
GitHub Stars
2
First Seen
Feb 4, 2026
Installed on
mcpjam3
claude-code3
replit3
junie3
windsurf3
zencoder3