
Git
- 48 installs
- 6 repo stars
- Updated July 22, 2026
- julianobarbosa/claude-code-skills
Master advanced Git workflows for history management, debugging, and collaboration.
About
Master advanced Git workflows including rebasing, cherry-picking, bisect, worktrees, and reflog to maintain clean history and recover from any situation.
- Cleaning up commit history before merging
- Applying specific commits across branches
Git by the numbers
- 48 all-time installs (skills.sh)
- +1 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #307 of 733 Git & Pull Requests skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/julianobarbosa/claude-code-skills --skill gitAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 48 |
|---|---|
| repo stars | ★ 6 |
| Last updated | July 22, 2026 |
| Repository | julianobarbosa/claude-code-skills ↗ |
What it does
Master advanced Git workflows for history management, debugging, and collaboration.
Files
Git Advanced Workflows
Master advanced Git techniques to maintain clean history, collaborate effectively, and recover from any situation with confidence.
When to Use This Skill
- Cleaning up commit history before merging
- Applying specific commits across branches
- Finding commits that introduced bugs
- Working on multiple features simultaneously
- Recovering from Git mistakes or lost commits
- Managing complex branch workflows
- Preparing clean PRs for review
- Synchronizing diverged branches
Core Concepts
1. Interactive Rebase
Interactive rebase is the Swiss Army knife of Git history editing.
Common Operations:
pick: Keep commit as-isreword: Change commit messageedit: Amend commit contentsquash: Combine with previous commitfixup: Like squash but discard messagedrop: Remove commit entirely
Basic Usage:
# Rebase last 5 commits
git rebase -i HEAD~5
# Rebase all commits on current branch
git rebase -i $(git merge-base HEAD main)
# Rebase onto specific commit
git rebase -i abc1232. Cherry-Picking
Apply specific commits from one branch to another without merging entire branches.
# Cherry-pick single commit
git cherry-pick abc123
# Cherry-pick range of commits (exclusive start)
git cherry-pick abc123..def456
# Cherry-pick without committing (stage changes only)
git cherry-pick -n abc123
# Cherry-pick and edit commit message
git cherry-pick -e abc1233. Git Bisect
Binary search through commit history to find the commit that introduced a bug.
# Start bisect
git bisect start
# Mark current commit as bad
git bisect bad
# Mark known good commit
git bisect good v1.0.0
# Git will checkout middle commit - test it
# Then mark as good or bad
git bisect good # or: git bisect bad
# Continue until bug found
# When done
git bisect resetAutomated Bisect:
# Use script to test automatically
git bisect start HEAD v1.0.0
git bisect run ./test.sh
# test.sh should exit 0 for good, 1-127 (except 125) for bad4. Worktrees
Work on multiple branches simultaneously without stashing or switching.
# List existing worktrees
git worktree list
# Add new worktree for feature branch
git worktree add ../project-feature feature/new-feature
# Add worktree and create new branch
git worktree add -b bugfix/urgent ../project-hotfix main
# Remove worktree
git worktree remove ../project-feature
# Prune stale worktrees
git worktree prune5. Reflog
Your safety net - tracks all ref movements, even deleted commits.
# View reflog
git reflog
# View reflog for specific branch
git reflog show feature/branch
# Restore deleted commit
git reflog
# Find commit hash
git checkout abc123
git branch recovered-branch
# Restore deleted branch
git reflog
git branch deleted-branch abc123Practical Workflows
Workflow 1: Clean Up Feature Branch Before PR
# Start with feature branch
git checkout feature/user-auth
# Interactive rebase to clean history
git rebase -i main
# Example rebase operations:
# - Squash "fix typo" commits
# - Reword commit messages for clarity
# - Reorder commits logically
# - Drop unnecessary commits
# Force push cleaned branch (safe if no one else is using it)
git push --force-with-lease origin feature/user-authWorkflow 2: Apply Hotfix to Multiple Releases
# Create fix on main
git checkout main
git commit -m "fix: critical security patch"
# Apply to release branches
git checkout release/2.0
git cherry-pick abc123
git checkout release/1.9
git cherry-pick abc123
# Handle conflicts if they arise
git cherry-pick --continue
# or
git cherry-pick --abortWorkflow 3: Find Bug Introduction
# Start bisect
git bisect start
git bisect bad HEAD
git bisect good v2.1.0
# Git checks out middle commit - run tests
npm test
# If tests fail
git bisect bad
# If tests pass
git bisect good
# Git will automatically checkout next commit to test
# Repeat until bug found
# Automated version
git bisect start HEAD v2.1.0
git bisect run npm testWorkflow 4: Multi-Branch Development
# Main project directory
cd ~/projects/myapp
# Create worktree for urgent bugfix
git worktree add ../myapp-hotfix hotfix/critical-bug
# Work on hotfix in separate directory
cd ../myapp-hotfix
# Make changes, commit
git commit -m "fix: resolve critical bug"
git push origin hotfix/critical-bug
# Return to main work without interruption
cd ~/projects/myapp
git fetch origin
git cherry-pick hotfix/critical-bug
# Clean up when done
git worktree remove ../myapp-hotfixWorkflow 5: Recover from Mistakes
# Accidentally reset to wrong commit
git reset --hard HEAD~5 # Oh no!
# Use reflog to find lost commits
git reflog
# Output shows:
# abc123 HEAD@{0}: reset: moving to HEAD~5
# def456 HEAD@{1}: commit: my important changes
# Recover lost commits
git reset --hard def456
# Or create branch from lost commit
git branch recovery def456Advanced Techniques
Rebase vs Merge Strategy
When to Rebase:
- Cleaning up local commits before pushing
- Keeping feature branch up-to-date with main
- Creating linear history for easier review
When to Merge:
- Integrating completed features into main
- Preserving exact history of collaboration
- Public branches used by others
# Update feature branch with main changes (rebase)
git checkout feature/my-feature
git fetch origin
git rebase origin/main
# Handle conflicts
git status
# Fix conflicts in files
git add .
git rebase --continue
# Or merge instead
git merge origin/mainAutosquash Workflow
Automatically squash fixup commits during rebase.
# Make initial commit
git commit -m "feat: add user authentication"
# Later, fix something in that commit
# Stage changes
git commit --fixup HEAD # or specify commit hash
# Make more changes
git commit --fixup abc123
# Rebase with autosquash
git rebase -i --autosquash main
# Git automatically marks fixup commitsSplit Commit
Break one commit into multiple logical commits.
# Start interactive rebase
git rebase -i HEAD~3
# Mark commit to split with 'edit'
# Git will stop at that commit
# Reset commit but keep changes
git reset HEAD^
# Stage and commit in logical chunks
git add file1.py
git commit -m "feat: add validation"
git add file2.py
git commit -m "feat: add error handling"
# Continue rebase
git rebase --continuePartial Cherry-Pick
Cherry-pick only specific files from a commit.
# Show files in commit
git show --name-only abc123
# Checkout specific files from commit
git checkout abc123 -- path/to/file1.py path/to/file2.py
# Stage and commit
git commit -m "cherry-pick: apply specific changes from abc123"Best Practices
1. Always Use --force-with-lease: Safer than --force, prevents overwriting others' work 2. Rebase Only Local Commits: Don't rebase commits that have been pushed and shared 3. Descriptive Commit Messages: Future you will thank present you 4. Atomic Commits: Each commit should be a single logical change 5. Test Before Force Push: Ensure history rewrite didn't break anything 6. Keep Reflog Aware: Remember reflog is your safety net for 90 days 7. Branch Before Risky Operations: Create backup branch before complex rebases
# Safe force push
git push --force-with-lease origin feature/branch
# Create backup before risky operation
git branch backup-branch
git rebase -i main
# If something goes wrong
git reset --hard backup-branchCommon Pitfalls
- Rebasing Public Branches: Causes history conflicts for collaborators
- Force Pushing Without Lease: Can overwrite teammate's work
- Losing Work in Rebase: Resolve conflicts carefully, test after rebase
- Forgetting Worktree Cleanup: Orphaned worktrees consume disk space
- Not Backing Up Before Experiment: Always create safety branch
- Bisect on Dirty Working Directory: Commit or stash before bisecting
Recovery Commands
# Abort operations in progress
git rebase --abort
git merge --abort
git cherry-pick --abort
git bisect reset
# Restore file to version from specific commit
git restore --source=abc123 path/to/file
# Undo last commit but keep changes
git reset --soft HEAD^
# Undo last commit and discard changes
git reset --hard HEAD^
# Recover deleted branch (within 90 days)
git reflog
git branch recovered-branch abc123Resources
- references/git-rebase-guide.md: Deep dive into interactive rebase
- references/git-conflict-resolution.md: Advanced conflict resolution strategies
- references/git-history-rewriting.md: Safely rewriting Git history
- assets/git-workflow-checklist.md: Pre-PR cleanup checklist
- assets/git-aliases.md: Useful Git aliases for advanced workflows
- scripts/git-clean-branches.sh: Clean up merged and stale branches
Conventional Commits Reference
A specification for adding human and machine-readable meaning to commit messages.
Format
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]Commit Types
| Type | Description | Semver Impact |
|---|---|---|
feat | New feature | MINOR |
fix | Bug fix | PATCH |
docs | Documentation only | None |
style | Code style (formatting, semicolons) | None |
refactor | Code change that neither fixes nor adds | None |
perf | Performance improvement | PATCH |
test | Adding/correcting tests | None |
build | Build system or dependencies | None |
ci | CI configuration files | None |
chore | Other changes (no src/test) | None |
revert | Reverts a previous commit | Varies |
Breaking Changes
Indicate breaking changes with:
!after type/scope:feat!: remove deprecated APIBREAKING CHANGE:in footer
feat(api)!: remove deprecated endpoints
BREAKING CHANGE: The /v1/users endpoint has been removed.
Use /v2/users instead.Scope Examples
Scope provides additional context:
feat(auth): add OAuth2 support
fix(parser): handle empty input
docs(readme): update installation steps
style(components): fix indentation
refactor(core): extract helper functions
perf(api): cache database queries
test(utils): add edge case tests
build(deps): update webpack to v5
ci(github): add automated release
chore(release): bump version to 2.0.0Good Commit Messages
Features
feat(cart): add quantity selector to cart items
Allow users to change item quantity directly in the cart
without returning to the product page.
Closes #142Bug Fixes
fix(auth): prevent session timeout during active use
The session was expiring even when users were actively
interacting with the application. Now activity resets
the timeout timer.
Fixes #256Breaking Change Examples
feat(api)!: change authentication to JWT
BREAKING CHANGE: Bearer token authentication now uses JWT.
All existing API keys will need to be regenerated.
Migration guide: docs/migration/v3-auth.mdReverts
revert: feat(cart): add quantity selector
This reverts commit abc1234.
Reason: Causes performance issues on mobile devices.
Will be reimplemented with lazy loading.Bad Commit Messages (Avoid)
# Too vague
fix: bug fix
update: updates
feat: new feature
# Not following convention
Fixed the login bug
Added new feature
WIPMulti-Line Messages
For complex changes, use body:
refactor(database): migrate from MySQL to PostgreSQL
- Updated connection pooling configuration
- Converted all raw queries to use parameterized statements
- Added migration scripts in /migrations
- Updated docker-compose for local development
Performance benchmarks show 15% improvement in read operations.
Related: #301, #302, #303Footer Conventions
| Footer | Purpose |
|---|---|
Fixes #123 | Closes issue on merge |
Closes #123 | Closes issue on merge |
Refs #123 | References without closing |
BREAKING CHANGE: | Describes breaking change |
Reviewed-by: Name | Code review attribution |
Co-authored-by: | Multiple authors |
Automation Benefits
Conventional commits enable:
1. Automatic changelog generation 2. Semantic versioning based on commit types 3. Filtered git history by type 4. CI/CD triggers based on commit type 5. Better code review with clear context
Quick Reference
# Feature
git commit -m "feat(scope): add new feature"
# Bug fix
git commit -m "fix(scope): resolve issue description"
# Documentation
git commit -m "docs(readme): update installation guide"
# Breaking change
git commit -m "feat(api)!: change endpoint structure
BREAKING CHANGE: /api/v1 is now /api/v2"
# With issue reference
git commit -m "fix(auth): resolve login timeout
Fixes #123"Resources
Git Best Practices Reference
Guidelines for effective Git usage in collaborative environments.
Commit Practices
Atomic Commits
Make each commit a single logical change:
# Good: Separate concerns
git add src/auth.js
git commit -m "feat(auth): add login validation"
git add src/auth.test.js
git commit -m "test(auth): add login validation tests"
# Bad: Mixed changes
git add .
git commit -m "add login and fix header and update styles"Commit Frequency
- Commit often, push regularly
- Each commit should compile and pass tests
- Don't commit broken code to shared branches
Meaningful History
# Review before committing
git diff --cached
# Amend last commit (before push)
git commit --amend
# Interactive rebase to clean history
git rebase -i HEAD~3Branch Strategy
Branch Naming
# Feature branches
feature/user-authentication
feature/JIRA-123-add-cart
# Bug fixes
fix/login-timeout
bugfix/header-alignment
# Hotfixes
hotfix/security-patch
# Releases
release/v2.0.0
# Experiments
experiment/new-algorithmBranch Lifecycle
# Create from updated main
git checkout main
git pull origin main
git checkout -b feature/new-feature
# Keep updated with main
git fetch origin
git rebase origin/main
# Delete after merge
git branch -d feature/new-feature
git push origin --delete feature/new-featureProtected Branches
main/master- Production-ready codedevelop- Integration branch- Never force push to protected branches
- Require pull request reviews
Pull Request Workflow
Before Opening PR
1. Rebase on latest main 2. Run all tests locally 3. Review your own changes 4. Write clear description
PR Description Template
## Summary
Brief description of changes
## Changes Made
- Added X feature
- Fixed Y bug
- Updated Z documentation
## Testing
- [ ] Unit tests added/updated
- [ ] Integration tests pass
- [ ] Manual testing completed
## Screenshots (if UI changes)
## Related Issues
Closes #123Review Process
1. Request specific reviewers 2. Address all feedback 3. Re-request review after changes 4. Squash commits if needed before merge
Merge Strategies
Merge Commit
git merge feature/branchPreserves full history. Good for feature branches.
Squash Merge
git merge --squash feature/branchCombines all commits into one. Good for cleanup.
Rebase Merge
git rebase main
git checkout main
git merge feature/branch --ff-onlyLinear history. Best for small changes.
When to Use Each
| Strategy | Use Case |
|---|---|
| Merge | Feature branches with meaningful commits |
| Squash | Messy history, WIP commits |
| Rebase | Linear history, small changes |
Conflict Resolution
Prevention
# Update frequently
git fetch origin
git rebase origin/main
# Communicate about shared files
# Keep changes focusedResolution Steps
# 1. Identify conflicts
git status
# 2. Open conflicted files
# Look for conflict markers:
# <<<<<<< HEAD
# your changes
# =======
# their changes
# >>>>>>> branch-name
# 3. Resolve manually or with tool
git mergetool
# 4. Stage resolved files
git add resolved-file.js
# 5. Continue operation
git rebase --continue
# or
git merge --continueGit Hooks
Common Hooks
# pre-commit: Run before commit
- Lint code
- Run tests
- Check formatting
# commit-msg: Validate message
- Enforce conventional commits
- Check length
# pre-push: Run before push
- Run full test suite
- Check for secretsSetup with Husky
// package.json
{
"husky": {
"hooks": {
"pre-commit": "npm run lint",
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
}
}Stash Best Practices
# Always name stashes
git stash push -m "WIP: feature X halfway done"
# List with context
git stash list
# Apply specific stash
git stash apply stash@{2}
# Clean up old stashes
git stash drop stash@{0}Tagging
Semantic Versioning
# Annotated tags (recommended)
git tag -a v1.0.0 -m "Release version 1.0.0"
# Push tags
git push origin v1.0.0
git push origin --tagsTag Naming
v1.0.0 # Release
v1.0.0-rc1 # Release candidate
v1.0.0-beta.1 # BetaRepository Hygiene
.gitignore
# Dependencies
node_modules/
vendor/
# Build outputs
dist/
build/
# Environment
.env
.env.local
# IDE
.idea/
.vscode/
# OS
.DS_Store
Thumbs.db
# Logs
*.log
logs/Large Files
# Use Git LFS for large files
git lfs install
git lfs track "*.psd"
git lfs track "*.zip"Repository Size
- Don't commit binaries
- Don't commit dependencies
- Don't commit build artifacts
- Use
.gitignoreaggressively
Collaboration Tips
Communication
- Write descriptive commit messages
- Document complex changes
- Comment on PRs constructively
Code Review
- Review promptly
- Be specific in feedback
- Approve when ready, not just okay
Synchronization
# Start of day
git fetch --all --prune
git pull origin main
# Before creating PR
git fetch origin
git rebase origin/mainTroubleshooting
Common Issues
# Undo last commit (keep changes)
git reset --soft HEAD~1
# Discard local changes
git checkout -- file.js
# Find lost commits
git reflog
# Recover deleted branch
git checkout -b recovered-branch abc1234Emergency Recovery
# Force update to remote state
git fetch origin
git reset --hard origin/main
# Cherry-pick specific commit
git cherry-pick abc1234Git Worktree Reference
Comprehensive guide for managing multiple working trees in a single repository.
What is a Worktree?
A Git worktree allows you to check out multiple branches simultaneously, each in its own directory. All worktrees share the same Git history and objects, but have independent working directories and index files.
Main Repository (.git)
│
├── main-worktree/ ← Branch: main
├── feature-worktree/ ← Branch: feature/auth
└── hotfix-worktree/ ← Branch: hotfix/urgentWhen to Use Worktrees
| Scenario | Benefit |
|---|---|
| Urgent hotfix while on feature branch | No stashing required, context preserved |
| Code review without losing work | Isolated review environment |
| Comparing behavior across branches | Side-by-side testing |
| Long-running builds | Continue development while building |
| Testing migrations | Run old and new code simultaneously |
| Parallel feature development | Multiple features without branch switching |
Core Commands Reference
List Worktrees
# Basic list
git worktree list
# Machine-readable format
git worktree list --porcelain
# Output example:
# /path/to/main abc1234 [main]
# /path/to/feature def5678 [feature/x]Add Worktree
# From existing branch
git worktree add <path> <branch>
# Create new branch in worktree
git worktree add -b <new-branch> <path> [start-point]
# Detached HEAD (specific commit)
git worktree add --detach <path> <commit>
# Track remote branch
git worktree add --track -b <local> <path> origin/<remote>Remove Worktree
# Standard removal (must be clean)
git worktree remove <path>
# Force removal (discards changes)
git worktree remove --force <path>
# Manual cleanup
rm -rf <path>
git worktree pruneMove Worktree
git worktree move <source> <destination>Lock/Unlock
# Lock (prevent pruning)
git worktree lock <path>
git worktree lock --reason "On external drive" <path>
# Unlock
git worktree unlock <path>Prune Stale References
# Remove stale entries
git worktree prune
# Dry run (preview)
git worktree prune --dry-run
# Verbose
git worktree prune -vRepair Worktree
# Repair admin files
git worktree repair [<path>...]Directory Organization Patterns
Sibling Pattern (Recommended)
~/projects/
├── my-project/ # Main worktree
├── my-project-feature-x/ # Feature worktree
├── my-project-hotfix/ # Hotfix worktree
└── my-project-review/ # Review worktreeNested Pattern
~/projects/
└── my-project/
├── main/ # Main branch
├── features/
│ ├── auth/ # feature/auth
│ └── api/ # feature/api
└── hotfixes/
└── critical/ # hotfix/criticalBare Repository Pattern
For heavy worktree usage:
# Clone as bare
git clone --bare https://github.com/user/repo.git repo.git
# Create worktrees from bare
cd repo.git
git worktree add ../main main
git worktree add ../develop developBest Practices
Do
1. Name worktrees descriptively - Include branch purpose in path 2. Prune regularly - Clean up stale references 3. Lock remote worktrees - Prevent accidental pruning 4. Keep structure flat - Avoid deeply nested worktrees 5. Share fetch results - One fetch updates all worktrees 6. Use for isolation - Keep unrelated work separated
Don't
1. Never delete main worktree - All others depend on it 2. Don't checkout same branch twice - Git prevents this 3. Don't nest worktrees - Creates confusion 4. Don't leave dirty worktrees - Clean up before removing 5. Don't ignore lock warnings - Check before forcing
Common Workflows
Emergency Hotfix
# Currently on feature branch
git worktree add -b hotfix/urgent ../hotfix main
# Fix issue
cd ../hotfix
# ... make changes ...
git commit -am "fix: critical issue"
git push origin hotfix/urgent
# Return to feature (context preserved)
cd ../my-projectCode Review
# Create review worktree
git fetch origin
git worktree add ../review-pr-123 origin/feature/pr-123
# Review
cd ../review-pr-123
# ... run tests, inspect code ...
# Cleanup
git worktree remove ../review-pr-123Parallel Builds
# Build multiple versions simultaneously
git worktree add ../build-staging staging
git worktree add ../build-prod production
# Parallel builds
cd ../build-staging && npm run build &
cd ../build-prod && npm run build &
waitError Troubleshooting
Branch Already Checked Out
Error: '<branch>' is already checked out at '<path>'Solutions:
1. Use a different branch name 2. Remove existing worktree: git worktree remove <path> 3. Force (dangerous): git checkout --ignore-other-worktrees
Path Already Exists
Error: '<path>' already existsSolutions:
1. Remove directory: rm -rf <path> 2. Choose different path 3. If valid worktree: git worktree repair <path>
Cannot Remove Dirty Worktree
Error: '<path>' contains modified or untracked filesSolutions:
1. Commit or stash changes first 2. Force remove: git worktree remove --force <path>
Stale Worktree Reference
Warning: worktree at '<path>' is missingSolution:
git worktree pruneWorktree Locked
Error: '<path>' is lockedSolutions:
1. Check reason: git worktree list 2. Unlock: git worktree unlock <path>
Performance Notes
| Aspect | Impact |
|---|---|
| Disk space | Shared .git objects, separate working copies |
| Memory | Each open IDE adds file watchers |
| Network | Single fetch updates all worktrees |
| CPU | Multiple builds can run in parallel |
Integration Tips
IDE Support
- VS Code: Open each worktree as separate workspace
- JetBrains: Use separate project windows
- vim/neovim: Works seamlessly with any worktree
CI/CD
# Status across all worktrees
for wt in $(git worktree list --porcelain | grep "^worktree" | cut -d' ' -f2); do
echo "=== $wt ==="
git -C "$wt" status -s
doneShell Aliases
# Add to ~/.bashrc or ~/.zshrc
alias gwl='git worktree list'
alias gwa='git worktree add'
alias gwr='git worktree remove'
alias gwp='git worktree prune'Quick Reference Card
| Command | Purpose |
|---|---|
git worktree list | List all worktrees |
git worktree add <path> <branch> | Add worktree for branch |
git worktree add -b <new> <path> | Add with new branch |
git worktree remove <path> | Remove worktree |
git worktree prune | Clean stale entries |
git worktree lock <path> | Prevent pruning |
git worktree repair | Fix admin files |
Security Checklist Reference
Pre-commit security verification to prevent sensitive data exposure.
Quick Scan Commands
# Check for common secrets patterns
git diff --cached | grep -iE "(api[_-]?key|secret|password|token|credential|private[_-]?key)"
# Check for environment files
git diff --cached --name-only | grep -E "\.env|\.env\.|config\.json|secrets\."
# Check for key files
git diff --cached --name-only | grep -E "\.(pem|key|p12|pfx|jks)$"Files to NEVER Commit
Environment Files
| File Pattern | Risk |
|---|---|
.env | API keys, database credentials |
.env.local | Local overrides with secrets |
.env.production | Production secrets |
.env.* | Any environment variant |
config.local.json | Local configuration |
Credential Files
| File Pattern | Risk |
|---|---|
*.pem | Private keys |
*.key | Private keys |
*.p12 | PKCS#12 certificates |
*.pfx | Windows certificates |
*.jks | Java keystores |
id_rsa* | SSH private keys |
*.ppk | PuTTY keys |
Cloud Provider Files
| File Pattern | Risk |
|---|---|
credentials | AWS credentials |
*.tfstate | Terraform state (may contain secrets) |
kubeconfig | Kubernetes access |
service-account.json | GCP service accounts |
IDE and Tool Files
| File Pattern | Risk |
|---|---|
.idea/ | May contain tokens |
.vscode/settings.json | May contain tokens |
*.code-workspace | May contain paths/tokens |
Sensitive Patterns to Detect
API Keys
# AWS
AKIA[0-9A-Z]{16}
# Google
AIza[0-9A-Za-z\-_]{35}
# GitHub
gh[pousr]_[A-Za-z0-9_]{36,255}
# Stripe
sk_live_[A-Za-z0-9]{24,}
rk_live_[A-Za-z0-9]{24,}
# Generic patterns
[aA][pP][iI][_-]?[kK][eE][yY].*['\"][A-Za-z0-9]{16,}['\"]Secrets and Passwords
# Password assignments
password\s*[:=]\s*['\"][^'\"]+['\"]
passwd\s*[:=]\s*['\"][^'\"]+['\"]
pwd\s*[:=]\s*['\"][^'\"]+['\"]
# Secret assignments
secret\s*[:=]\s*['\"][^'\"]+['\"]
api_secret\s*[:=]\s*['\"][^'\"]+['\"]Tokens
# JWT tokens
eyJ[A-Za-z0-9-_]+\.eyJ[A-Za-z0-9-_]+
# Bearer tokens
[Bb]earer\s+[A-Za-z0-9\-_]+
# OAuth tokens
access_token\s*[:=]\s*['\"][^'\"]+['\"]
refresh_token\s*[:=]\s*['\"][^'\"]+['\"]Private Keys
-----BEGIN (RSA |EC |DSA |OPENSSH |)PRIVATE KEY-----
-----BEGIN PGP PRIVATE KEY BLOCK-----Database URLs
# PostgreSQL
postgres(ql)?://[^:]+:[^@]+@
# MySQL
mysql://[^:]+:[^@]+@
# MongoDB
mongodb(\+srv)?://[^:]+:[^@]+@
# Redis
redis://:[^@]+@Pre-Commit Verification Script
#!/bin/bash
# save as .git/hooks/pre-commit
echo "Running security check..."
# Patterns to check
PATTERNS=(
"password\s*[:=]"
"api[_-]?key\s*[:=]"
"secret\s*[:=]"
"token\s*[:=]"
"AKIA[0-9A-Z]{16}"
"-----BEGIN.*PRIVATE KEY-----"
"sk_live_"
"rk_live_"
)
# Files to block
BLOCKED_FILES=(
"\.env$"
"\.env\."
"\.pem$"
"\.key$"
"id_rsa"
"credentials$"
)
# Check staged files
STAGED=$(git diff --cached --name-only)
# Check for blocked files
for pattern in "${BLOCKED_FILES[@]}"; do
if echo "$STAGED" | grep -qE "$pattern"; then
echo "ERROR: Attempting to commit sensitive file matching: $pattern"
exit 1
fi
done
# Check content for secrets
for pattern in "${PATTERNS[@]}"; do
if git diff --cached | grep -qiE "$pattern"; then
echo "WARNING: Potential secret detected matching: $pattern"
echo "Please review staged changes carefully."
read -p "Continue anyway? (y/N) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
exit 1
fi
fi
done
echo "Security check passed."
exit 0Recommended .gitignore
# Environment files
.env
.env.*
!.env.example
!.env.template
# Credentials
*.pem
*.key
*.p12
*.pfx
*.jks
id_rsa*
*.ppk
# Cloud credentials
credentials
.aws/
.gcloud/
kubeconfig
**/terraform.tfstate
**/terraform.tfstate.*
**/.terraform/
# IDE settings that may contain tokens
.idea/
.vscode/settings.json
*.code-workspace
# Logs that may contain sensitive info
*.log
logs/
# Local config
config.local.*
secrets.*Tools for Secret Detection
git-secrets (AWS)
# Install
brew install git-secrets
# Setup
git secrets --install
git secrets --register-aws
# Scan
git secrets --scangitleaks
# Install
brew install gitleaks
# Scan repository
gitleaks detect
# Scan staged changes
gitleaks protect --stagedtruffleHog
# Install
pip install truffleHog
# Scan
trufflehog git file://./If Secrets Are Committed
Immediate Actions
1. Revoke the secret immediately
- Generate new API key/password
- Update all systems using it
2. Remove from history (if not pushed)
git reset --soft HEAD~1
# Remove secret from files
git add .
git commit -m "chore: remove sensitive data"3. If already pushed - Consider it compromised
- Rotate credentials first
- Then clean history with BFG or git filter-branch
- Force push (coordinate with team)
Using BFG Repo-Cleaner
# Install BFG
brew install bfg
# Remove file from history
bfg --delete-files .env
# Remove secrets by pattern
bfg --replace-text patterns.txt
# Clean and force push
git reflog expire --expire=now --all
git gc --prune=now --aggressive
git push --forceSecurity Mindset
Before Every Commit
1. Review staged changes: git diff --cached 2. Check file names: git diff --cached --name-only 3. Run security scan if available 4. Ask: "Would I want this public?"
Environment Best Practices
1. Use .env.example with placeholder values 2. Document required environment variables 3. Use secret management tools (Vault, AWS Secrets Manager) 4. Rotate credentials regularly
Code Review Checklist
- [ ] No hardcoded credentials
- [ ] No API keys in source
- [ ] No private keys included
- [ ] Environment variables used for config
- [ ] Logging doesn't expose secrets
- [ ] Error messages don't leak secrets
Branch Workflow
Create, switch, list, and manage Git branches.
Prerequisites
- Git repository initialized
- For remote operations: remote configured
Operations
List Branches
# List local branches
git branch
# List all branches (local + remote)
git branch -a
# List remote branches only
git branch -r
# List with last commit info
git branch -v
# List merged branches
git branch --merged
# List unmerged branches
git branch --no-mergedCreate New Branch
From current HEAD:
# Create branch
git branch <branch-name>
# Create and switch to branch
git checkout -b <branch-name>
# Or using switch (Git 2.23+)
git switch -c <branch-name>From specific commit/branch:
# Create from another branch
git checkout -b <new-branch> <source-branch>
# Create from specific commit
git checkout -b <new-branch> <commit-hash>
# Create from tag
git checkout -b <new-branch> <tag-name>From remote branch:
# Fetch first
git fetch origin
# Create tracking branch
git checkout -b <local-name> origin/<remote-branch>
# Or track with same name
git checkout --track origin/<branch-name>Switch Branches
# Switch to existing branch
git checkout <branch-name>
# Or using switch (Git 2.23+)
git switch <branch-name>
# Switch to previous branch
git checkout -
git switch -Before switching:
# Check for uncommitted changes
git status
# If changes exist, either:
# 1. Commit them
git add -A && git commit -m "wip: save progress"
# 2. Stash them
git stash push -m "switching branches"
# 3. Discard them (CAUTION)
git checkout -- .Rename Branch
# Rename current branch
git branch -m <new-name>
# Rename specific branch
git branch -m <old-name> <new-name>
# Update remote (delete old, push new)
git push origin --delete <old-name>
git push -u origin <new-name>Delete Branch
Local branch:
# Safe delete (only if merged)
git branch -d <branch-name>
# Force delete (even if unmerged)
git branch -D <branch-name>Remote branch:
# Delete remote branch
git push origin --delete <branch-name>
# Or using colon syntax
git push origin :<branch-name>Track Remote Branch
# Set upstream for current branch
git branch --set-upstream-to=origin/<branch>
# Or during push
git push -u origin <branch-name>
# Check tracking info
git branch -vvBranch Naming Conventions
| Type | Format | Example |
|---|---|---|
| Feature | feature/<description> | feature/user-auth |
| Bug fix | fix/<description> | fix/login-error |
| Hotfix | hotfix/<description> | hotfix/security-patch |
| Release | release/<version> | release/v1.2.0 |
| Chore | chore/<description> | chore/update-deps |
Rules:
- Use lowercase
- Use hyphens, not underscores
- Keep names concise but descriptive
- Include ticket number if applicable:
feature/JIRA-123-user-auth
Common Workflows
Start New Feature
# Ensure you're on main with latest
git checkout main
git pull origin main
# Create feature branch
git checkout -b feature/new-feature
# Work and commit...
git add -A
git commit -m "feat: add new feature"
# Push to remote
git push -u origin feature/new-featureClean Up Merged Branches
# Delete merged local branches
git branch --merged main | grep -v "main" | xargs git branch -d
# Prune remote tracking branches
git fetch --prune
# Delete merged remote branches (careful!)
git branch -r --merged main | grep -v "main" | sed 's/origin\///' | xargs -I {} git push origin --delete {}Find Branch Containing Commit
# Find branches containing commit
git branch --contains <commit-hash>
# Find remote branches
git branch -r --contains <commit-hash>Safety Rules
1. Check status before switching - Don't lose uncommitted work 2. Don't delete unmerged branches without understanding why 3. Be careful with remote deletes - Others may depend on them 4. Keep main/master protected - Never work directly on it 5. Prune regularly - Clean up stale branches
Error Handling
Branch Already Exists
Error: Branch already exists.
Options:
1. Use different name
2. Delete existing: git branch -D <name>
3. Switch to it: git checkout <name>Uncommitted Changes Block Switch
Error: Your local changes would be overwritten.
Options:
1. Commit: git add -A && git commit -m "wip"
2. Stash: git stash
3. Discard: git checkout -- . (CAUTION)Cannot Delete Current Branch
Error: Cannot delete the branch you're on.
Switch to another branch first:
git checkout main
Then delete:
git branch -d <branch>Commit Workflow
Stage all changes and create a commit locally (NO push to remote).
Prerequisites
- Git repository initialized
- Changes to commit (staged or unstaged)
Workflow Steps
Step 1: Security Scan
CRITICAL: Scan for sensitive data before ANY commit.
# Check for sensitive files in staged changes
git diff --cached --name-only | grep -iE '\.(env|pem|key|p12|pfx|credentials)$'
# Check for hardcoded secrets in staged content
git diff --cached | grep -iE '(api[_-]?key|secret|password|token|credential).*=.*["\047][a-zA-Z0-9]'If sensitive data found:
1. STOP immediately 2. Report findings to user 3. Suggest using .gitignore or removing secrets 4. DO NOT proceed until resolved
Step 2: Review Changes
# Show current status
git status
# Show detailed diff of all changes
git diff
git diff --cachedReview checklist:
- [ ] No sensitive data (credentials, API keys, tokens)
- [ ] No
.envfiles or variants - [ ] No private keys or certificates
- [ ] No database connection strings with passwords
- [ ] Changes are intentional and complete
Step 3: Generate Commit Message
Follow Conventional Commits format:
<type>(<scope>): <short description>
<optional body with details>Type Selection Guide:
| Changes Include | Type |
|---|---|
| New feature or capability | feat |
| Bug fix | fix |
| Documentation only | docs |
| Code formatting/style | style |
| Code restructure | refactor |
| Performance improvement | perf |
| Test changes | test |
| Build/dependency changes | build |
| CI/CD changes | ci |
| Maintenance/chores | chore |
Rules:
- Title: Max 70 characters, imperative mood, no period
- Scope: Optional, describes affected area (e.g.,
api,ui,auth) - Body: Explain what and why, not how
Step 4: Stage and Commit
# Stage all changes
git add -A
# Or stage specific files
git add <file1> <file2>
# Commit with message
git commit -m "<type>(<scope>): <description>"For multi-line commit messages:
git commit -m "<title>" -m "<body paragraph>"Step 5: Verify Success
# Show the new commit
git log -1 --oneline
# Confirm clean working directory (or remaining changes)
git statusOutput Format
Commit successful!
Hash: <commit-hash>
Message: <commit-message>
Files changed: <count>
Insertions: <count>
Deletions: <count>
Working directory: [clean | <remaining changes>]Special Cases
Splitting Changes Into Multiple Commits
If changes span multiple concerns:
1. Stage related files together 2. Commit with appropriate type 3. Repeat for remaining changes
# Commit feature files
git add src/feature/*
git commit -m "feat(feature): add new capability"
# Commit test files
git add tests/feature/*
git commit -m "test(feature): add tests for new capability"Amending Previous Commit
Only if NOT pushed to remote:
# Add changes to previous commit
git add <files>
git commit --amend --no-edit
# Or update the message
git commit --amend -m "new message"IMPORTANT
This workflow does NOT push to remote.
To push after committing, use the CommitPush workflow or run:
git push origin <branch>CommitPush Workflow
Stage all changes, create a commit, and push to remote repository.
Prerequisites
- Git repository initialized
- Remote configured (
origin) - Changes to commit
- Push access to remote
Workflow Steps
Step 1: Security Scan
CRITICAL: Scan for sensitive data before ANY commit.
# Check for sensitive files
git diff --cached --name-only | grep -iE '\.(env|pem|key|p12|pfx|credentials)$'
git diff --name-only | grep -iE '\.(env|pem|key|p12|pfx|credentials)$'
# Check for hardcoded secrets
git diff --cached | grep -iE '(api[_-]?key|secret|password|token|credential).*=.*["\047][a-zA-Z0-9]'
git diff | grep -iE '(api[_-]?key|secret|password|token|credential).*=.*["\047][a-zA-Z0-9]'If sensitive data found:
1. STOP immediately 2. Report all findings to user 3. DO NOT proceed until resolved 4. Suggest .gitignore additions if needed
Step 2: Verify Remote
# Confirm remote URL
git remote -v
# Confirm current branch
git branch --show-currentSafety check: Verify this is the intended repository before pushing sensitive code.
Step 3: Review Changes
# Full status
git status
# Detailed changes
git diff
git diff --cachedReview checklist:
- [ ] No credentials or API keys
- [ ] No
.envfiles - [ ] No private keys or certificates
- [ ] No connection strings with passwords
- [ ] All changes are intentional
Step 4: Generate Commit Message
Conventional Commits format:
<type>(<scope>): <description>
[optional body]Type selection:
feat: New featurefix: Bug fixdocs: Documentation onlystyle: Formattingrefactor: Code restructureperf: Performancetest: Testingbuild: Build/depsci: CI/CDchore: Maintenance
Rules:
- Title max 70 characters
- Imperative mood ("add" not "added")
- No period at end
Step 5: Stage and Commit
# Stage all changes
git add -A
# Commit
git commit -m "<type>(<scope>): <description>"Step 6: Push to Remote
# Push to origin on current branch
git push origin $(git branch --show-current)If branch doesn't exist on remote:
git push -u origin $(git branch --show-current)Step 7: Verify Push
# Confirm push succeeded
git log origin/$(git branch --show-current) -1 --oneline
# Check sync status
git statusOutput Format
Commit and push successful!
Commit:
Hash: <commit-hash>
Message: <commit-message>
Push:
Remote: origin
Branch: <branch-name>
URL: <repository-url>
Files changed: <count>
Insertions: <count>
Deletions: <count>Error Handling
Push Rejected - Behind Remote
# Fetch and rebase
git fetch origin
git rebase origin/<branch>
# Then push
git push origin <branch>Push Rejected - Protected Branch
Error: Cannot push directly to protected branch.
Options:
1. Create a feature branch and open a PR
2. Request push access from repository adminAuthentication Failed
Error: Authentication required.
Solutions:
1. Check SSH key: ssh -T git@github.com
2. Check token: gh auth status
3. Re-authenticate: gh auth loginSplitting Into Multiple Commits
If changes span multiple concerns, split them:
# First commit - features
git add src/features/*
git commit -m "feat: add new feature"
# Second commit - tests
git add tests/*
git commit -m "test: add feature tests"
# Push all commits
git push origin <branch>NEVER Do
1. Force push to main/master without explicit confirmation 2. Push secrets or credentials - always scan first 3. Skip the security scan - it's mandatory 4. Add AI attribution to commit messages
Diff Workflow
Compare changes between commits, branches, or working directory.
Prerequisites
- Git repository initialized
- Something to compare
Basic Diff Commands
# Unstaged changes
git diff
# Staged changes
git diff --cached
git diff --staged
# All changes (staged + unstaged)
git diff HEADDiff Types
Working Directory Diffs
# Unstaged vs last commit
git diff
# Specific file
git diff path/to/file.js
# Specific directory
git diff src/Staged Diffs
# Staged vs last commit
git diff --cached
# Staged specific file
git diff --cached path/to/file.jsCommit Diffs
# Between two commits
git diff abc1234 def5678
# Parent to commit
git diff abc1234^..abc1234
# Last commit changes
git diff HEAD~1Branch Diffs
# Current vs another branch
git diff main
# Between two branches
git diff main..feature/branch
# What's in branch but not main
git diff main...feature/branchDiff Output Formats
Standard Patch
git diffdiff --git a/file.js b/file.js
index abc1234..def5678 100644
--- a/file.js
+++ b/file.js
@@ -10,7 +10,8 @@ function example() {
console.log("before");
- oldCode();
+ newCode();
+ additionalCode();
console.log("after");
}Stat Summary
git diff --stat src/app.js | 10 +++++-----
src/utils.js | 5 +++++
tests/app.js | 3 +--
3 files changed, 11 insertions(+), 7 deletions(-)Short Stat
git diff --shortstat 3 files changed, 11 insertions(+), 7 deletions(-)Name Only
git diff --name-onlysrc/app.js
src/utils.js
tests/app.jsName Status
git diff --name-statusM src/app.js
A src/utils.js
D tests/old.js
R old-name.js -> new-name.jsStatus codes: M=Modified, A=Added, D=Deleted, R=Renamed, C=Copied
Advanced Diff Options
Word Diff
# Color words instead of lines
git diff --word-diff
# Plain format
git diff --word-diff=plainIgnore Whitespace
# Ignore all whitespace
git diff -w
# Ignore at end of line
git diff --ignore-space-at-eol
# Ignore amount of whitespace
git diff -bContext Control
# Show more/less context lines
git diff -U10 # 10 lines of context
git diff -U0 # No contextBinary Diffs
# Show binary file changes
git diff --binary
# Just note that binary changed
git diff --statCommon Scenarios
What Did I Change?
# All uncommitted changes
git diff
# Just file names
git diff --name-onlyWhat's Staged?
# Staged changes
git diff --cached
# Stats
git diff --cached --statCompare Branches
# Current vs main
git diff main
# What's different in feature
git diff main..feature/branch --statReview PR Changes
# All changes in PR
git diff main...feature/branch
# Specific file in PR
git diff main...feature/branch -- path/to/fileFind Changed Functions
# Show function context
git diff -p --function-contextCheck Specific Commit
# What changed in commit
git diff abc1234^..abc1234
# Or simpler
git show abc1234Compare Across Time
# File at two points
git diff HEAD~10:path/to/file HEAD:path/to/file
# Or between dates
git diff $(git rev-list -1 --before="1 week ago" HEAD) HEADDiff Tools
External Diff Tool
# Use configured difftool
git difftool
# Use specific tool
git difftool --tool=vscodeConfigure Difftool
# Set default
git config --global diff.tool vscode
git config --global difftool.vscode.cmd 'code --wait --diff $LOCAL $REMOTE'Output Format
Present diffs as:
Changes Summary
───────────────
Files Changed: 3
Insertions: +15
Deletions: -8
Modified Files:
M src/app.js (+10, -5)
A src/utils.js (+5)
D tests/old.js (-3)
Details:
[Show relevant diff snippets]Quick Reference
| Purpose | Command |
|---|---|
| Unstaged changes | git diff |
| Staged changes | git diff --cached |
| All changes | git diff HEAD |
| Between commits | git diff A B |
| Between branches | git diff main..branch |
| Stats only | git diff --stat |
| File names only | git diff --name-only |
| Word-level diff | git diff --word-diff |
| Ignore whitespace | git diff -w |
| Specific file | git diff -- file |
Three-Dot vs Two-Dot
# Two dots: Direct comparison
git diff A..B
# Shows what B has that A doesn't
# Three dots: Common ancestor comparison
git diff A...B
# Shows what B has since diverging from AUse three dots for PR reviews (what changed in feature branch since branching).
Log Workflow
View commit history and logs.
Prerequisites
- Git repository initialized
- Commits to view
Basic Log Commands
# Default log
git log
# One line per commit
git log --oneline
# With graph
git log --oneline --graph
# All branches
git log --oneline --graph --allLog Formatting
Compact Formats
# One line
git log --oneline
# Short format
git log --format=short
# Full format
git log --format=full
# Custom format
git log --format="%h %an %s"Custom Format Placeholders
| Placeholder | Meaning |
|---|---|
%H | Full commit hash |
%h | Short hash |
%an | Author name |
%ae | Author email |
%ad | Author date |
%ar | Author date (relative) |
%cn | Committer name |
%s | Subject (first line) |
%b | Body |
%d | Ref names |
Example custom format:
git log --format="%h - %an, %ar : %s"
# abc1234 - John Doe, 2 days ago : Add featureVisual Formats
# Graph view
git log --graph --oneline --all
# Decorated (show branches/tags)
git log --oneline --decorate
# Stat summary
git log --stat
# Full patch
git log -pFiltering Logs
By Count
# Last N commits
git log -5
# Skip first N
git log --skip=5 -10By Date
# After date
git log --after="2024-01-01"
# Before date
git log --before="2024-12-31"
# Date range
git log --after="2024-01-01" --before="2024-06-30"
# Relative dates
git log --after="2 weeks ago"
git log --since="yesterday"By Author
# By author name
git log --author="John"
# By email
git log --author="john@example.com"
# Multiple authors
git log --author="John\|Jane"By Message
# Search in commit message
git log --grep="bug fix"
# Case insensitive
git log --grep="BUG" -i
# Regex
git log --grep="^feat:"By File
# Commits affecting file
git log -- path/to/file.js
# Multiple files
git log -- src/*.js tests/*.js
# Renamed files
git log --follow -- new-name.jsBy Content
# Commits changing specific string
git log -S"functionName"
# With regex
git log -G"function.*Name"By Branch/Range
# Commits in branch not in main
git log main..feature/branch
# Commits in either, not both
git log main...feature/branch
# Commits reachable from branch
git log feature/branchCommon Use Cases
View Recent Activity
git log --oneline -20Find When Something Changed
# When was file changed
git log --oneline -- path/to/file
# What changed in file
git log -p -- path/to/fileFind Who Changed Something
# Line-by-line blame
git blame path/to/file
# With log
git log --format="%h %an %s" -- path/to/fileReview PR Commits
# Commits in branch vs main
git log main..feature/branch --oneline
# With changes
git log main..feature/branch -pFind Breaking Commit
# Bisect for bug introduction
git bisect start
git bisect bad HEAD
git bisect good v1.0.0
# Test each commit Git checks out
git bisect good # or bad
git bisect resetDaily Standup Log
# My commits since yesterday
git log --author="$(git config user.name)" --since="yesterday" --onelineOutput Format
Present log results as:
Commit History
──────────────
Recent commits (last 10):
abc1234 2h ago John Doe feat: add user auth
def5678 1d ago Jane Smith fix: resolve login bug
ghi9012 2d ago John Doe docs: update README
Summary:
Total: 10 commits
Authors: 2
Date range: Dec 20 - Dec 25, 2024Useful Aliases
# Add to ~/.gitconfig
[alias]
lg = log --oneline --graph --decorate
ll = log --format='%h %an %s' -10
hist = log --pretty=format:'%h %ad | %s%d [%an]' --date=short
today = log --since=midnight --oneline
week = log --since='1 week ago' --onelineQuick Reference
| Purpose | Command |
|---|---|
| Last 10 commits | git log --oneline -10 |
| Graph view | git log --oneline --graph --all |
| By author | git log --author="name" |
| By date | git log --after="date" |
| By file | git log -- file |
| Search message | git log --grep="text" |
| Search content | git log -S"code" |
| Branch diff | git log main..branch |
| With changes | git log -p |
| Stats only | git log --stat |
Merge Workflow
Merge branches together safely.
Prerequisites
- Git repository initialized
- Branches to merge exist
- Clean working directory recommended
Basic Merge
Standard Merge (with commit)
# Ensure you're on target branch
git checkout main
# Merge source branch
git merge feature/my-featureThis creates a merge commit preserving branch history.
Fast-Forward Merge
# When target hasn't diverged
git merge --ff-only feature/my-featureThis moves the pointer forward without a merge commit.
No Fast-Forward (Force Merge Commit)
# Always create merge commit
git merge --no-ff feature/my-featureUseful for maintaining clear feature boundaries in history.
Merge Workflow Steps
Step 1: Prepare for Merge
# Check current status
git status
# Ensure working directory is clean
# If not, commit or stash changes
# Switch to target branch
git checkout main
# Update target branch
git pull origin mainStep 2: Preview Merge
# See what will be merged
git log main..feature/branch --oneline
# See file changes
git diff main...feature/branch --stat
# Dry run (check for conflicts without merging)
git merge --no-commit --no-ff feature/branch
git merge --abort # Cancel previewStep 3: Execute Merge
# Merge the branch
git merge feature/my-feature -m "Merge feature/my-feature into main"Step 4: Verify Merge
# Check status
git status
# View merge commit
git log -1
# Verify changes
git diff HEAD~1Step 5: Push Merged Result
git push origin mainHandling Merge Conflicts
When Conflicts Occur
# Git will report conflicting files
git status
# Files with conflicts shown as:
# both modified: <filename>Resolve Conflicts
1. Open conflicting files - Look for conflict markers:
<<<<<<< HEAD
your changes
=======
incoming changes
>>>>>>> feature/branch2. Edit to resolve - Keep desired code, remove markers
3. Mark as resolved:
git add <resolved-file>4. Complete merge:
git commitAbort Merge
# Cancel merge and return to pre-merge state
git merge --abortUse Merge Tool
# Open configured merge tool
git mergetool
# Common tools: vimdiff, meld, kdiff3, vscodeMerge Strategies
Recursive (Default)
git merge -s recursive feature/branchBest for most merges, handles renames well.
Ours (Keep Target)
git merge -s ours feature/branchKeeps all changes from current branch, discards source changes. Use case: Marking a branch as merged without taking changes.
Theirs (Keep Source)
git merge -X theirs feature/branchPrefers changes from source branch in conflicts.
Octopus (Multi-branch)
git merge branch1 branch2 branch3Merge multiple branches at once (no conflict resolution).
Squash Merge
Combine all commits into one:
# Squash merge (no commit yet)
git merge --squash feature/branch
# Commit the squashed changes
git commit -m "feat: add feature (squashed)"Pros: Clean history, single commit Cons: Loses individual commit details
Common Merge Scenarios
Merge Main into Feature (Update Feature)
# On feature branch
git checkout feature/my-feature
# Merge main
git merge main
# Resolve any conflicts
# Push updated feature branch
git push origin feature/my-featureMerge Feature into Main (Complete Feature)
# On main branch
git checkout main
git pull origin main
# Merge feature
git merge --no-ff feature/my-feature
# Push
git push origin main
# Delete feature branch (optional)
git branch -d feature/my-feature
git push origin --delete feature/my-featureMerge Release Branch
# Merge to main
git checkout main
git merge --no-ff release/v1.0 -m "Release v1.0"
git tag -a v1.0 -m "Version 1.0"
git push origin main --tags
# Merge back to develop
git checkout develop
git merge --no-ff release/v1.0
git push origin developSafety Rules
1. Always update target branch first - Pull before merge 2. Check for uncommitted work - Clean working directory 3. Preview before merging - Know what's coming 4. Don't force push after merge - Others may have pulled 5. Test after merge - Ensure nothing broke 6. Use `--no-ff` for features - Maintain clear history
Error Handling
Merge Conflict
CONFLICT (content): Merge conflict in <file>
Automatic merge failed.
Resolution:
1. Edit conflicting files
2. git add <resolved-files>
3. git commitCannot Fast-Forward
Error: Not possible to fast-forward.
Options:
1. Allow merge commit: git merge <branch>
2. Rebase instead: git rebase <branch>
3. Force FF (loses commits): Not recommendedNothing to Merge
Already up to date.
The branches are identical - no merge needed.PullRequest Workflow
Create a pull request using GitHub CLI.
Prerequisites
- Git repository with GitHub remote
- GitHub CLI (
gh) installed and authenticated - Feature branch with commits to merge
- Push access to repository
Arguments
| Argument | Description | Default |
|---|---|---|
TO_BRANCH | Target branch for PR | main |
FROM_BRANCH | Source branch | Current branch |
Workflow Steps
Step 1: Verify Prerequisites
# Check gh CLI is available
gh --version
# Check authentication
gh auth status
# Verify current branch
git branch --show-currentIf `gh` not available:
GitHub CLI is required for this workflow.
Install:
macOS: brew install gh
Linux: sudo apt install gh
Windows: winget install GitHub.cli
Then authenticate:
gh auth loginStep 2: Ensure Branch is Pushed
# Get current branch
BRANCH=$(git branch --show-current)
# Check if branch exists on remote
git fetch origin
# Push if needed
git push -u origin $BRANCHStep 3: Gather PR Information
# Get commits in this branch vs target
git log origin/main..HEAD --oneline
# Get changed files
git diff origin/main --stat
# Get full diff for summary
git diff origin/mainStep 4: Generate PR Content
Title format:
<type>(<scope>): <concise description>Description template:
## Summary
<2-3 bullet points describing what this PR does>
## Changes
<List of key changes>
## Testing
<How this was tested>
## Checklist
- [ ] Tests pass
- [ ] Documentation updated (if needed)
- [ ] No breaking changes (or documented)Step 5: Create Pull Request
# Create PR with title and body
gh pr create \
--title "<type>(<scope>): <description>" \
--body "$(cat <<'EOF'
## Summary
- <change 1>
- <change 2>
- <change 3>
## Changes
<detailed changes>
## Testing
<testing approach>
EOF
)" \
--base main \
--head $(git branch --show-current)With reviewers:
gh pr create \
--title "<title>" \
--body "<body>" \
--base main \
--reviewer @username1,@username2As draft:
gh pr create \
--title "<title>" \
--body "<body>" \
--base main \
--draftStep 6: Verify PR Created
# Show PR details
gh pr view
# Get PR URL
gh pr view --json url -q .urlOutput Format
Pull Request created!
PR #<number>: <title>
URL: <pr-url>
From: <source-branch>
To: <target-branch>
Commits: <count>
Files changed: <count>
Additions: <count>
Deletions: <count>
Status: [Draft | Ready for review]Advanced Options
Create PR with Labels
gh pr create \
--title "<title>" \
--body "<body>" \
--label "enhancement" \
--label "needs-review"Create PR with Milestone
gh pr create \
--title "<title>" \
--body "<body>" \
--milestone "v1.0"Create PR with Project
gh pr create \
--title "<title>" \
--body "<body>" \
--project "Sprint 1"Create PR Linking Issues
gh pr create \
--title "fix: resolve login issue" \
--body "Fixes #123
## Summary
- Fixed authentication bug
- Added error handling"Error Handling
Branch Not Pushed
Error: Branch not found on remote.
Run: git push -u origin $(git branch --show-current)No Commits to Merge
Error: No commits between main and current branch.
The branches are identical. Make commits before creating a PR.PR Already Exists
Error: PR already exists for this branch.
View existing PR: gh pr view
Or close it first: gh pr closeNot Authenticated
Error: Not authenticated with GitHub.
Run: gh auth login
And follow the prompts.PR Best Practices
1. Keep PRs focused - One feature/fix per PR 2. Write clear descriptions - Help reviewers understand changes 3. Link related issues - Use "Fixes #123" syntax 4. Request specific reviewers - Don't rely on auto-assignment 5. Use draft PRs - For work-in-progress 6. Respond to feedback - Address comments promptly
Rebase Workflow
Reapply commits on top of another base.
Prerequisites
- Git repository initialized
- Understanding of rebase implications
- Never rebase public/shared branches
Understanding Rebase
Rebase rewrites commit history by:
1. Taking your commits 2. Temporarily removing them 3. Applying target branch commits 4. Replaying your commits on top
Result: Linear history without merge commits.
Basic Rebase
Rebase onto Branch
# On feature branch
git checkout feature/my-feature
# Rebase onto main
git rebase mainRebase onto Remote
# Fetch latest
git fetch origin
# Rebase onto remote main
git rebase origin/mainRebase Workflow Steps
Step 1: Prepare
# Ensure clean working directory
git status
# Switch to branch to rebase
git checkout feature/my-feature
# Fetch latest from remote
git fetch originStep 2: Execute Rebase
# Rebase onto main
git rebase mainStep 3: Handle Conflicts (if any)
# Git pauses at conflicts
# Edit files to resolve
# After resolving:
git add <resolved-files>
git rebase --continue
# Or abort:
git rebase --abortStep 4: Force Push (if already pushed)
DANGER: Only do this on YOUR branch:
# Force push rebased branch
git push --force-with-lease origin feature/my-featureInteractive Rebase
Rewrite, reorder, squash, or drop commits.
Start Interactive Rebase
# Rebase last N commits
git rebase -i HEAD~5
# Rebase onto branch interactively
git rebase -i mainInteractive Commands
pick - Use commit as-is
reword - Use commit but edit message
edit - Stop for amending
squash - Meld into previous commit (keep message)
fixup - Meld into previous commit (discard message)
drop - Remove commitCommon Interactive Operations
Squash multiple commits:
git rebase -i HEAD~3
# In editor:
pick abc1234 First commit
squash def5678 Second commit
squash ghi9012 Third commit
# Save, then edit combined messageReword commit message:
git rebase -i HEAD~2
# Change 'pick' to 'reword'
reword abc1234 Old message
# Save, then edit message in next editorReorder commits:
git rebase -i HEAD~3
# Simply reorder the lines
pick ghi9012 Third commit
pick abc1234 First commit
pick def5678 Second commitDrop a commit:
git rebase -i HEAD~3
# Change 'pick' to 'drop' or delete the line
pick abc1234 First commit
drop def5678 Second commit
pick ghi9012 Third commitRebase vs Merge
| Aspect | Rebase | Merge |
|---|---|---|
| History | Linear | Preserves branches |
| Conflicts | Per commit | Once |
| Safety | Rewrites history | Safe for shared |
| Use case | Clean up before merge | Integrate branches |
Golden rule: Only rebase commits that haven't been pushed/shared.
Common Scenarios
Update Feature Branch with Main
# On feature branch
git checkout feature/my-feature
# Fetch and rebase
git fetch origin
git rebase origin/main
# Force push if needed
git push --force-with-lease origin feature/my-featureClean Up Before PR
# Squash WIP commits
git rebase -i main
# Make commits logical units
# Force push cleaned branch
git push --force-with-lease origin feature/my-featureSplit a Commit
git rebase -i HEAD~2
# Mark commit as 'edit'
edit abc1234 Large commit
# When stopped:
git reset HEAD~
git add <first-part>
git commit -m "first change"
git add <second-part>
git commit -m "second change"
git rebase --continueHandling Conflicts
During Rebase
# Git pauses at conflict
# Files shown in git status
# Resolve conflicts in files
# Remove conflict markers
# Stage resolved files
git add <file>
# Continue rebase
git rebase --continueAbort Rebase
# Return to pre-rebase state
git rebase --abortSkip Problematic Commit
# Skip current commit
git rebase --skipSafety Rules
1. NEVER rebase public branches (main, develop) 2. NEVER rebase commits others have based work on 3. Use `--force-with-lease` not --force 4. Backup before complex rebases: git branch backup-branch 5. Understand the commits before rebasing
Error Handling
Nothing to Rebase
Current branch is up to date.
Already rebased or no new commits to apply.Conflicts During Rebase
CONFLICT (content): Merge conflict in <file>
Resolve:
1. Edit file
2. git add <file>
3. git rebase --continue
Or abort: git rebase --abortDiverged After Force Push
Error: Others have pulled the old version.
Solutions:
1. Coordinate with team to reset
2. Never rebase shared branches againAutosquash
Automatically squash fixup commits:
# Create fixup commit
git commit --fixup=<commit-hash>
# Rebase with autosquash
git rebase -i --autosquash mainGit automatically arranges fixup commits.
Stash Workflow
Temporarily save uncommitted changes.
Prerequisites
- Git repository initialized
- Uncommitted changes to stash
Understanding Stash
Stash saves your working directory and index state without committing. This lets you switch context and return later.
Use cases:
- Switch branches with uncommitted work
- Pull changes without committing WIP
- Temporarily set aside experiments
- Save partial work before meetings
Basic Operations
Save to Stash
# Stash all tracked changes
git stash
# Stash with message
git stash push -m "description of changes"
# Stash including untracked files
git stash push -u -m "including new files"
# Stash including ignored files
git stash push -a -m "everything"List Stashes
# Show all stashes
git stash list
# Output format:
# stash@{0}: WIP on main: abc1234 Last commit message
# stash@{1}: On feature: def5678 Another commitApply Stash
# Apply most recent stash (keep in stash)
git stash apply
# Apply specific stash
git stash apply stash@{2}
# Apply and remove from stash
git stash pop
# Pop specific stash
git stash pop stash@{1}View Stash Contents
# Show changes in most recent stash
git stash show
# Show with diff
git stash show -p
# Show specific stash
git stash show -p stash@{1}Delete Stash
# Drop most recent stash
git stash drop
# Drop specific stash
git stash drop stash@{2}
# Clear all stashes
git stash clearStash Workflow Steps
Step 1: Identify What to Stash
# Check current state
git status
# See what will be stashed
git diff
git diff --cachedStep 2: Stash Changes
# With descriptive message
git stash push -m "WIP: feature implementation"
# For new files too
git stash push -u -m "WIP: new feature with new files"Step 3: Verify Stash
# Confirm stash created
git stash list
# Confirm working directory clean
git statusStep 4: Do Other Work
# Switch branches, pull, etc.
git checkout other-branch
git pull origin mainStep 5: Restore Stash
# Return to original branch
git checkout original-branch
# Apply stash
git stash popAdvanced Stash Operations
Stash Specific Files
# Stash only certain files
git stash push -m "partial stash" -- file1.js file2.js
# Stash everything except certain files
git stash push -m "most changes" -- . ':(exclude)keep-this.js'Create Branch from Stash
# Create new branch with stash applied
git stash branch new-feature-branch stash@{0}Useful when stash conflicts with current branch.
Stash Staged Only
# Keep unstaged, stash only staged
git stash push --staged -m "staged changes only"Stash Keep Index
# Stash but keep staged changes in index
git stash push --keep-index -m "unstaged only"Interactive Stash
# Interactively select hunks to stash
git stash push -p -m "selected changes"Common Scenarios
Quick Context Switch
# Working on feature, need to check something on main
git stash push -m "feature WIP"
git checkout main
# ... do stuff ...
git checkout feature-branch
git stash popPull with Local Changes
# Can't pull with uncommitted changes
git stash push -m "before pull"
git pull origin main
git stash pop
# Resolve any conflictsTry Something Experimental
# Save current work
git stash push -m "stable version"
# Experiment
# ... make risky changes ...
# If it fails, restore
git checkout -- .
git stash pop
# If it works, commit and drop stash
git add -A && git commit -m "feat: experimental change"
git stash dropRecover Dropped Stash
# Find the stash SHA
git fsck --unreachable | grep commit
# Or from reflog
git reflog
# Apply by SHA
git stash apply <commit-sha>Stash vs Commit
| Stash | Commit |
|---|---|
| Temporary | Permanent |
| Not shared | Pushed to remote |
| No message required | Message required |
| Quick context switch | Logical checkpoint |
| Stack based (LIFO) | Linear history |
Rule of thumb:
- Stash: "I need to do something else quickly"
- Commit: "This is a meaningful unit of work"
Error Handling
No Local Changes to Stash
No local changes to save.
Working directory is already clean.Conflicts When Applying
CONFLICT: Merge conflict in <file>
Resolution:
1. Resolve conflicts in files
2. git add <resolved-files>
3. Continue work (stash is not dropped if using apply)Stash Index Out of Range
Error: stash@{5} is not a valid reference
Check available stashes: git stash listBest Practices
1. Always add messages - Future you will thank you 2. Don't stash for too long - Commit or branch instead 3. Check stash list regularly - Clean up old stashes 4. Use branches for longer work - Stash is for quick switches 5. Include untracked if needed - Use -u flag
Status Workflow
Check repository status, changes, and sync state.
Prerequisites
- Git repository initialized
Basic Status
# Full status
git status
# Short format
git status -s
# With branch tracking info
git status -sbStatus Output Explained
Full Status Format
On branch main
Your branch is ahead of 'origin/main' by 2 commits.
Changes to be committed:
(staged)
modified: file1.js
new file: file2.js
Changes not staged for commit:
(unstaged)
modified: file3.js
deleted: file4.js
Untracked files:
(new files not yet added)
file5.jsShort Status Format
M file1.js # Modified (unstaged)
M file2.js # Modified (staged)
MM file3.js # Modified (staged + unstaged)
A file4.js # Added (staged)
D file5.js # Deleted (unstaged)
D file6.js # Deleted (staged)
?? file7.js # Untracked
!! ignored.js # IgnoredPosition meanings:
- First column: Staged changes
- Second column: Unstaged changes
Workflow Steps
Step 1: Check Overall Status
# Get full picture
git status
# Quick view
git status -sbStep 2: Review Specific Changes
# Unstaged changes
git diff
# Staged changes
git diff --cached
# All changes (staged + unstaged)
git diff HEADStep 3: Check Remote Sync
# Fetch remote info
git fetch origin
# Check ahead/behind
git status
# Detailed comparison
git log origin/main..HEAD --oneline # Local not on remote
git log HEAD..origin/main --oneline # Remote not in localStep 4: List Changed Files
# Names only
git diff --name-only
# With status
git diff --name-status
# Stats summary
git diff --statDetailed Status Commands
Branch Information
# Current branch
git branch --show-current
# All branches with details
git branch -vv
# Remote tracking info
git remote show originCommit Status
# Last commit
git log -1
# Unpushed commits
git log origin/main..HEAD --oneline
# Commits to pull
git log HEAD..origin/main --onelineFile Status
# Check specific file
git status -- path/to/file
# List ignored files
git status --ignored
# Show ignored too (short)
git status -s --ignoredWorktree Status
# Check if in repo
git rev-parse --is-inside-work-tree
# Get repo root
git rev-parse --show-toplevel
# Current directory relative to root
git rev-parse --show-prefixCommon Status Scenarios
Clean Working Directory
On branch main
Your branch is up to date with 'origin/main'.
nothing to commit, working tree cleanReady to Commit
On branch feature/xyz
Changes to be committed:
modified: src/app.js
new file: src/utils.js
All staged - ready for: git commitNeed to Stage
On branch feature/xyz
Changes not staged for commit:
modified: src/app.js
Stage with: git add src/app.jsAhead of Remote
Your branch is ahead of 'origin/main' by 3 commits.
Push with: git push origin mainBehind Remote
Your branch is behind 'origin/main' by 2 commits.
Pull with: git pull origin mainDiverged
Your branch and 'origin/main' have diverged,
and have 2 and 3 different commits each.
Options:
1. Merge: git pull origin main
2. Rebase: git rebase origin/mainOutput Format
Provide status in this structured format:
Repository Status
─────────────────
Branch: <current-branch>
Remote: <tracking-branch>
Status: [Clean | Changes pending | Conflicts]
Sync Status:
Ahead: <count> commits
Behind: <count> commits
Changes:
Staged:
- <file1> (modified)
- <file2> (new file)
Unstaged:
- <file3> (modified)
- <file4> (deleted)
Untracked:
- <file5>
- <file6>
Recommendations:
- <action to take>Quick Commands Reference
| Command | Purpose |
|---|---|
git status | Full status |
git status -s | Short format |
git status -sb | Short with branch |
git diff | Unstaged changes |
git diff --cached | Staged changes |
git diff --stat | Summary stats |
git log -1 | Last commit |
git branch -vv | Branch tracking |
Safety Checks
Before major operations, always check:
1. Current branch - Am I on the right branch? 2. Uncommitted changes - Will they be lost? 3. Sync status - Am I up to date with remote? 4. Staged vs unstaged - What exactly will be committed?
Sync Workflow
Synchronize local branch with remote repository.
Prerequisites
- Git repository initialized
- Remote configured (origin)
- Network access to remote
Basic Sync Operations
Fetch (Download Only)
# Fetch all branches
git fetch origin
# Fetch specific branch
git fetch origin main
# Fetch and prune deleted branches
git fetch --prune originPull (Fetch + Merge)
# Pull current branch
git pull origin $(git branch --show-current)
# Pull with rebase
git pull --rebase origin main
# Pull and autostash
git pull --autostash origin mainPush (Upload)
# Push current branch
git push origin $(git branch --show-current)
# Push and set upstream
git push -u origin $(git branch --show-current)
# Push all branches
git push origin --allSync Workflow Steps
Step 1: Check Current State
# Current branch
git branch --show-current
# Current sync status
git status
# Uncommitted changes?
git status --porcelainStep 2: Fetch Latest
# Get latest from remote
git fetch origin
# Check what's new
git log HEAD..origin/$(git branch --show-current) --onelineStep 3: Review Changes
# See what will be pulled
git log HEAD..origin/main --oneline
# See file changes
git diff HEAD..origin/main --statStep 4: Pull Changes
# Standard pull (merge)
git pull origin main
# Or with rebase (cleaner history)
git pull --rebase origin mainStep 5: Push Local Changes
# Push to remote
git push origin $(git branch --show-current)Step 6: Verify Sync
# Confirm up to date
git statusSync Strategies
Merge Strategy (Default)
git pull origin mainCreates merge commit if diverged. Preserves all history.
Rebase Strategy
git pull --rebase origin mainReplays your commits on top of remote. Linear history.
Set as default:
git config pull.rebase trueFast-Forward Only
git pull --ff-only origin mainFails if not fast-forwardable. Safest option.
Common Scenarios
Update Feature Branch from Main
# On feature branch
git checkout feature/my-feature
# Fetch latest main
git fetch origin main
# Rebase onto main
git rebase origin/main
# Force push if already pushed
git push --force-with-lease origin feature/my-featureSync Fork with Upstream
# Add upstream remote (once)
git remote add upstream https://github.com/original/repo.git
# Fetch upstream
git fetch upstream
# Merge upstream into local main
git checkout main
git merge upstream/main
# Push to your fork
git push origin mainRecover from Diverged State
# Option 1: Merge (keeps both histories)
git pull origin main
# Option 2: Rebase (linear history)
git fetch origin
git rebase origin/main
# Option 3: Reset to remote (LOSES local commits)
# DANGER - only if local commits are disposable
git fetch origin
git reset --hard origin/mainPull with Local Changes
# Option 1: Stash, pull, pop
git stash push -m "before pull"
git pull origin main
git stash pop
# Option 2: Autostash
git pull --autostash origin main
# Option 3: Commit first
git add -A
git commit -m "wip: save before pull"
git pull origin mainHandling Conflicts
During Pull
# Conflicts shown after pull
git status
# Resolve conflicts in files
# Remove conflict markers
# Stage resolved files
git add <file>
# Complete merge
git commitDuring Rebase
# Conflicts during rebase
git status
# Resolve conflicts
git add <file>
# Continue rebase
git rebase --continue
# Or abort
git rebase --abortSafety Features
Force Push Protection
# Use --force-with-lease (safer than --force)
git push --force-with-lease origin feature/branchThis fails if remote has new commits you haven't fetched.
Before Pull Checklist
1. Check for uncommitted changes: git status 2. Stash or commit them 3. Verify you're on correct branch 4. Fetch first to preview: git fetch origin
Error Handling
Push Rejected
Error: Updates were rejected because the remote contains work
that you do not have locally.
Resolution:
git pull origin <branch>
# Resolve any conflicts
git push origin <branch>Cannot Pull with Local Changes
Error: Your local changes would be overwritten by merge.
Options:
1. Commit: git add -A && git commit -m "wip"
2. Stash: git stash push -m "before pull"
3. Discard: git checkout -- . (CAUTION)Divergent Branches
Error: Branches have diverged.
Options:
1. Merge: git pull origin main
2. Rebase: git pull --rebase origin main
3. Reset: git reset --hard origin/main (DANGER)Quick Reference
| Task | Command |
|---|---|
| Fetch all | git fetch origin |
| Pull current | git pull |
| Pull with rebase | git pull --rebase |
| Push current | git push |
| Push new branch | git push -u origin <branch> |
| Sync fork | git fetch upstream && git merge upstream/main |
| Force push safely | git push --force-with-lease |
Undo Workflow
Undo changes, reset commits, and revert modifications.
Prerequisites
- Git repository initialized
- Understanding of what you want to undo
Safety Classification
| Operation | Destructive | Recoverable |
|---|---|---|
checkout -- file | YES | NO* |
reset --soft | NO | YES |
reset --mixed | NO | YES |
reset --hard | YES | Partial** |
revert | NO | YES |
clean -fd | YES | NO |
Uncommitted changes lost permanently *Commits recoverable via reflog for ~30 days
Undo Uncommitted Changes
Discard Changes in File
# Discard changes in specific file
git checkout -- <file>
# Or using restore (Git 2.23+)
git restore <file>
# Discard all unstaged changes
git checkout -- .
git restore .WARNING: This permanently deletes uncommitted changes.
Unstage Files
# Unstage specific file
git reset HEAD <file>
# Or using restore
git restore --staged <file>
# Unstage all files
git reset HEAD
git restore --staged .Changes remain in working directory.
Discard All Changes
# Unstaged changes
git checkout -- .
# Staged and unstaged
git reset --hard HEAD
# Including untracked files (DANGER)
git clean -fdUndo Commits
Undo Last Commit (Keep Changes)
# Uncommit but keep changes staged
git reset --soft HEAD~1
# Uncommit and unstage (keep in working dir)
git reset HEAD~1
# or
git reset --mixed HEAD~1Undo Last Commit (Discard Changes)
# Remove commit AND changes (DANGER)
git reset --hard HEAD~1Undo Multiple Commits
# Undo last 3 commits (keep changes)
git reset HEAD~3
# Undo to specific commit
git reset <commit-hash>Undo Pushed Commit (Safe)
# Create new commit that undoes changes
git revert <commit-hash>
git push origin <branch>This is safe for shared branches.
Undo Pushed Commit (Rewrite History)
# DANGER: Only for personal branches
git reset --hard HEAD~1
git push --force-with-lease origin <branch>NEVER do this on main/master or shared branches.
Undo Merge
Undo Unpushed Merge
# If you haven't committed merge yet
git merge --abort
# If merge is committed
git reset --hard HEAD~1Undo Pushed Merge
# Revert the merge commit
git revert -m 1 <merge-commit-hash>
git push origin <branch>-m 1 means keep parent 1 (the branch you merged into).
Undo Rebase
During Rebase
# Abort rebase in progress
git rebase --abortAfter Rebase
# Use reflog to find pre-rebase state
git reflog
# Reset to before rebase
git reset --hard HEAD@{2}Recovery with Reflog
# Show recent HEAD positions
git reflog
# Output:
# abc1234 HEAD@{0}: reset: moving to HEAD~1
# def5678 HEAD@{1}: commit: some work
# ghi9012 HEAD@{2}: commit: earlier work
# Recover to specific point
git reset --hard HEAD@{1}Workflow Steps
Step 1: Understand What to Undo
# Check current state
git status
# Check recent commits
git log --oneline -10
# Check reflog
git reflog -10Step 2: Choose Undo Method
| What to Undo | Method |
|---|---|
| Unstaged file changes | git checkout -- <file> |
| Staged files | git reset HEAD <file> |
| Last commit (keep changes) | git reset HEAD~1 |
| Last commit (discard) | git reset --hard HEAD~1 |
| Pushed commit | git revert <hash> |
| Merge | git revert -m 1 <hash> |
| Rebase | git reflog + git reset |
Step 3: Execute with Confirmation
Always confirm destructive operations:
WARNING: This will permanently delete uncommitted changes.
Proceed? [y/N]Step 4: Verify Result
# Check status
git status
# Check commit history
git log --oneline -5
# Check file contents
git diffCommon Scenarios
Accidentally Staged Wrong File
git restore --staged wrong-file.js
# File is now unstaged but changes preservedCommitted to Wrong Branch
# On wrong branch, move commit to correct branch
git checkout correct-branch
git cherry-pick <commit-hash>
# Remove from wrong branch
git checkout wrong-branch
git reset --hard HEAD~1Need to Edit Last Commit
# Add forgotten changes
git add forgotten-file.js
git commit --amend --no-edit
# Or change the message
git commit --amend -m "new message"Only if not pushed yet.
Accidentally Deleted File
# If still uncommitted
git checkout -- deleted-file.js
# If committed
git checkout HEAD~1 -- deleted-file.jsReset Too Far
# Find the commit you need
git reflog
# Restore to that point
git reset --hard <hash>Error Handling
Cannot Reset - Changes Would Be Overwritten
Error: Your local changes would be overwritten.
Options:
1. Stash: git stash
2. Commit: git commit -am "wip"
3. Discard: git checkout -- .Cannot Revert - Conflicts
Error: Conflict during revert.
Resolution:
1. Resolve conflicts
2. git add <files>
3. git revert --continueReflog Entry Not Found
Error: Cannot find HEAD@{n}
Reflog entries expire after ~30 days.
Commits may be recoverable with:
git fsck --lost-foundSafety Checklist
Before any undo operation:
- [ ] Do I understand what will be lost?
- [ ] Have I backed up important changes?
- [ ] Is this a shared branch? (If yes, use
revert) - [ ] Have I checked the reflog for recovery options?
Worktree Workflow
Create, manage, and work with multiple working trees simultaneously.
Overview
Git worktrees allow you to check out multiple branches at once, each in its own directory. This enables parallel development without stashing changes or creating multiple clones.
Prerequisites
- Git 2.5+ installed
- Git repository initialized
- Sufficient disk space for additional working directories
Operations
List Worktrees
# List all worktrees
git worktree list
# Verbose output with more details
git worktree list --porcelainOutput example:
/path/to/main-repo abc1234 [main]
/path/to/feature-tree def5678 [feature/auth]
/path/to/hotfix-tree ghi9012 [hotfix/urgent]Add New Worktree
From existing branch:
# Add worktree for existing branch
git worktree add <path> <branch>
# Example
git worktree add ../feature-auth feature/user-authenticationCreate new branch in worktree:
# Add worktree with new branch
git worktree add -b <new-branch> <path> [<start-point>]
# Example: new branch from main
git worktree add -b feature/new-feature ../new-feature main
# Example: new branch from current HEAD
git worktree add -b hotfix/urgent ../hotfix-urgentFrom detached HEAD:
# Checkout specific commit without branch
git worktree add --detach <path> <commit>
# Example
git worktree add --detach ../investigate abc1234From remote branch:
# Fetch first
git fetch origin
# Create worktree tracking remote branch
git worktree add -b local-name <path> origin/remote-branch
# Or track with same name
git worktree add --track -b feature/x ../feature-x origin/feature/xRemove Worktree
Standard removal:
# Remove worktree (after it's clean)
git worktree remove <path>
# Example
git worktree remove ../feature-authForce removal:
# Force remove (discards changes)
git worktree remove --force <path>
# Or manually delete and prune
rm -rf <path>
git worktree pruneMove Worktree
# Move worktree to new location
git worktree move <source> <destination>
# Example
git worktree move ../old-location ../new-locationLock/Unlock Worktree
Prevent worktree from being pruned (useful for removable drives or network mounts):
# Lock worktree
git worktree lock <path>
git worktree lock --reason "On external drive" <path>
# Unlock worktree
git worktree unlock <path>
# List shows locked status
git worktree listPrune Stale Worktrees
# Remove stale worktree references
git worktree prune
# Dry run - see what would be pruned
git worktree prune --dry-run
# Verbose output
git worktree prune -vRepair Worktree
# Repair worktree admin files
git worktree repair [<path>...]
# Repair from within worktree
cd /path/to/worktree
git worktree repairCommon Workflows
Parallel Feature Development
# Start from main repo
cd /path/to/main-repo
# Create worktree for new feature
git worktree add -b feature/auth ../auth-feature main
# Work in the new worktree
cd ../auth-feature
# ... make changes, commit ...
# Meanwhile, in another terminal, work on main repo
cd /path/to/main-repo
# ... different work here ...Hotfix While Working on Feature
# Currently working on feature branch
pwd
# /path/to/project
# Create hotfix worktree without losing context
git worktree add -b hotfix/critical ../hotfix main
# Fix the issue
cd ../hotfix
# ... apply fix ...
git commit -am "fix: critical security issue"
git push origin hotfix/critical
# Return to feature work
cd /path/to/project
# Context preserved!Code Review in Separate Directory
# Create worktree for PR review
git fetch origin
git worktree add ../review-pr-123 origin/feature/pr-123
# Review the code
cd ../review-pr-123
# ... run tests, inspect code ...
# Clean up after review
git worktree remove ../review-pr-123Testing Different Versions
# Create worktrees for multiple versions
git worktree add ../v1.0 v1.0.0
git worktree add ../v2.0 v2.0.0
git worktree add ../main-test main
# Run comparative tests across versionsBuild Different Branches Simultaneously
# Create worktrees for parallel builds
git worktree add ../build-staging staging
git worktree add ../build-prod production
# Run builds in parallel (different terminals)
cd ../build-staging && npm run build &
cd ../build-prod && npm run build &Directory Structure Best Practices
Recommended layout:
~/projects/
├── my-project/ # Main worktree (bare or with main branch)
├── my-project-feature-x/ # Feature worktree
├── my-project-hotfix/ # Hotfix worktree
└── my-project-review/ # Review worktreeOr nested approach:
~/projects/
└── my-project/
├── main/ # Main branch
├── features/
│ ├── auth/ # feature/auth
│ └── api/ # feature/api
└── hotfixes/
└── critical/ # hotfix/criticalBare Repository Pattern
For heavy worktree usage, consider a bare repository:
# Clone as bare repo
git clone --bare https://github.com/user/repo.git repo.git
# Create worktrees from bare repo
cd repo.git
git worktree add ../main main
git worktree add ../develop develop
git worktree add ../feature ../feature feature/x
# Main worktree list
git worktree listSafety Rules
1. Never delete main worktree - All others depend on it 2. Check for uncommitted changes before removing worktrees 3. Prune regularly - Clean up stale references 4. Lock remote worktrees - Prevent accidental pruning 5. Avoid nested worktrees - Keep directory structure flat 6. Don't checkout same branch twice - Git prevents this
Error Handling
Branch Already Checked Out
Error: '<branch>' is already checked out at '<path>'
This is a safety feature. Options:
1. Use a different branch
2. Remove existing worktree: git worktree remove <path>
3. Force (DANGER): git checkout --ignore-other-worktreesWorktree Path Already Exists
Error: '<path>' already exists
Options:
1. Remove existing directory: rm -rf <path>
2. Choose different path
3. If it's a valid worktree: git worktree repair <path>Stale Worktree Reference
Warning: worktree at '<path>' is missing
Run:
git worktree pruneCannot Remove Dirty Worktree
Error: '<path>' contains modified or untracked files
Options:
1. Commit or stash changes
2. Force remove: git worktree remove --force <path>Worktree Locked
Error: '<path>' is locked
Check lock reason:
git worktree list
Unlock if safe:
git worktree unlock <path>Performance Considerations
- Disk space: Each worktree shares .git objects but has its own working copy
- Memory: Multiple worktrees = multiple file watchers if IDE is open
- Network: Only one fetch needed - all worktrees share objects
- IDE integration: Some IDEs handle worktrees better than others
Integration with Other Commands
# Show status across all worktrees
for wt in $(git worktree list --porcelain | grep "^worktree" | cut -d' ' -f2); do
echo "=== $wt ==="
git -C "$wt" status -s
done
# Fetch updates for all worktrees (only needed once)
git fetch --all
# Push from any worktree (all share same remote config)
git push origin feature/branch