# Git Command Reference

Comprehensive git reference for daily development workflows, multi-remote setups, and recovery patterns.

---

## Table of Contents

1. [Setup and Configuration](#setup-and-configuration)
2. [Basic Snapshotting](#basic-snapshotting)
3. [Branching and Merging](#branching-and-merging)
4. [Remote Management](#remote-management)
5. [Multi-Remote Workflows](#multi-remote-workflows)
6. [Rebase Workflows](#rebase-workflows)
7. [Stash Operations](#stash-operations)
8. [Cherry-Pick and Patching](#cherry-pick-and-patching)
9. [Reset and Restore](#reset-and-restore)
10. [Safety and Recovery](#safety-and-recovery)
11. [Debugging with Bisect](#debugging-with-bisect)
12. [Worktree Management](#worktree-management)
13. [Common Workflow Patterns](#common-workflow-patterns)

---

## Setup and Configuration

### Repository initialization

```bash
git init                          # Initialize new repo
git clone <url>                   # Clone existing repo
git clone --bare <url>            # Clone as bare (for mirrors)
git clone --depth 1 <url>         # Shallow clone (latest commit only)
```

### Configuration levels

```bash
git config --global user.name "Name"
git config --global user.email "email@example.com"
git config --local core.autocrlf input
git config --list --show-origin   # Show all config with source files
```

### Useful config options

```bash
git config --global pull.rebase true           # Rebase on pull instead of merge
git config --global push.default current       # Push current branch to same name
git config --global rebase.autoSquash true     # Enable autosquash by default
git config --global rebase.autoStash true      # Auto-stash before rebase
git config --global fetch.prune true           # Auto-prune stale remote refs
git config --global diff.algorithm histogram   # Better diff output
git config --global merge.conflictstyle diff3  # Show base in conflicts
```

---

## Basic Snapshotting

### Status and diff

```bash
git status                        # Working tree status
git status -sb                    # Short format with branch info
git diff                          # Unstaged changes
git diff --staged                 # Staged changes (same as --cached)
git diff HEAD                     # All changes since last commit
git diff --stat                   # Summary of changes
git diff --name-only              # Just filenames
git diff branch1..branch2         # Diff between branches
git diff branch1...branch2        # Changes since branch2 diverged from branch1
```

### Adding and committing

```bash
git add <file>                    # Stage specific file
git add -p                        # Interactive staging by hunk
git add -N <file>                 # Mark intent to add (for new files in diff)
git commit -m "message"           # Commit with message
git commit --amend                # Amend last commit
git commit --amend --no-edit      # Amend without changing message
git commit --fixup <sha>          # Create fixup commit for autosquash
git commit --allow-empty -m "msg" # Empty commit (CI triggers, etc.)
```

### Removing and moving

```bash
git rm <file>                     # Remove from index and working tree
git rm --cached <file>            # Remove from index only (untrack)
git mv <old> <new>                # Rename/move tracked file
```

### Log

```bash
git log --oneline                 # Compact log
git log --graph --oneline --all   # Branch topology
git log -n 5                      # Last 5 commits
git log --since="2 weeks ago"     # Time-based filtering
git log --author="name"           # Filter by author
git log -- <file>                 # History of specific file
git log -p -- <file>              # With diffs for file
git log --follow -- <file>        # Follow renames
git log branch1..branch2          # Commits in branch2 not in branch1
git log branch1...branch2         # Symmetric difference
git shortlog -sn                  # Contributor summary
```

---

## Branching and Merging

### Branch operations

```bash
git branch                        # List local branches
git branch -a                     # List all (local + remote)
git branch -vv                    # Show tracking info
git branch <name>                 # Create branch
git branch -d <name>              # Delete (safe, checks merge status)
git branch -D <name>              # Force delete
git branch -m <old> <new>         # Rename branch
git branch --merged               # Branches merged into current
git branch --no-merged            # Branches not yet merged
```

### Switching branches

```bash
git switch <branch>               # Switch to branch (modern)
git switch -c <new-branch>        # Create and switch
git switch -c <new> <start>       # Create from specific point
git checkout <branch>             # Switch (legacy, still works)
git checkout -b <new-branch>      # Create and switch (legacy)
```

### Merging

```bash
git merge <branch>                # Merge branch into current
git merge --no-ff <branch>        # Force merge commit (no fast-forward)
git merge --squash <branch>       # Squash all commits into one staged change
git merge --abort                 # Abort in-progress merge
git merge --continue              # Continue after conflict resolution
git merge -X theirs <branch>      # Auto-resolve conflicts favoring theirs
git merge -X ours <branch>        # Auto-resolve conflicts favoring ours
```

### Tags

```bash
git tag v1.0.0                    # Lightweight tag
git tag -a v1.0.0 -m "Release"   # Annotated tag
git tag -d v1.0.0                 # Delete local tag
git push origin v1.0.0            # Push specific tag
git push origin --tags            # Push all tags
git push origin :v1.0.0           # Delete remote tag
```

---

## Remote Management

### Viewing remotes

```bash
git remote -v                     # List remotes with URLs
git remote show <name>            # Detailed remote info
git remote get-url <name>         # Get fetch URL
git remote get-url --push <name>  # Get push URL
git remote get-url --all <name>   # All URLs
```

### Adding and modifying remotes

```bash
git remote add <name> <url>       # Add remote
git remote remove <name>          # Remove remote
git remote rename <old> <new>     # Rename remote
git remote set-url <name> <url>   # Change URL
git remote set-url --push <name> <url>  # Set push-only URL
git remote set-url --add <name> <url>   # Add additional URL
```

### Fetching

```bash
git fetch <remote>                # Fetch from remote
git fetch --all                   # Fetch from all remotes
git fetch --prune                 # Remove stale remote-tracking refs
git fetch <remote> <branch>       # Fetch specific branch
```

### Pulling

```bash
git pull                          # Fetch + merge (or rebase if configured)
git pull --rebase                 # Fetch + rebase
git pull <remote> <branch>        # Pull specific branch
git pull --autostash              # Auto-stash dirty tree
```

### Pushing

```bash
git push <remote> <branch>        # Push branch
git push -u <remote> <branch>     # Push and set upstream tracking
git push <remote> HEAD            # Push current branch by name
git push --all <remote>           # Push all branches
git push --tags <remote>          # Push all tags
git push --follow-tags            # Push commits + reachable annotated tags
git push <remote> --delete <branch>  # Delete remote branch
git push <remote> :<branch>       # Delete remote branch (refspec)
```

### Refspec syntax

```bash
# Format: [+]<src>:<dst>
git push origin main:main         # Explicit source:destination
git push origin main:deploy       # Push local main to remote deploy
git push origin HEAD:main         # Push current branch to remote main
git push origin :old-branch       # Delete remote branch
git push origin +main             # Force push (+ prefix)
```

---

## Multi-Remote Workflows

### Three-remote setup (private dev, public release, deploy)

```bash
# Add remotes
git remote add origin git@gitea.local:user/project.git   # Private dev
git remote add github git@github.com:user/project.git    # Public release
git remote add deploy git@github.com:org/deploy.git      # Deploy target

# Verify
git remote -v
```

### Fetching from multiple remotes

```bash
git fetch --all                   # Fetch all remotes at once
git fetch origin                  # Fetch only private dev
git fetch github                  # Fetch only public

# Compare local to each remote
git log origin/main..HEAD         # Commits not yet on private remote
git log github/main..HEAD         # Commits not yet on public remote
```

### Pushing to specific remotes

```bash
# Daily development: push to private
git push origin main

# Publishing: push to public (use publish script for safety)
git push github main

# Push a tag to public only
git push github v1.0.0

# Push branch to multiple remotes
git push origin feature-branch
git push github feature-branch
```

### Tracking branches across remotes

```bash
# Set upstream to private remote
git branch --set-upstream-to=origin/main main

# Check what tracks what
git branch -vv

# Create local branch tracking a specific remote
git switch -c hotfix origin/hotfix
git switch -c public-feature github/feature
```

### Selective publishing

```bash
# Push only specific branches to public
git push github main
git push github --tags

# Never push private branches to public
# Use .github-exclude or publish scripts to enforce

# Cherry-pick public-worthy commits to a clean branch
git switch -c release main
git cherry-pick <commit1> <commit2>
git push github release:main
```

### Keeping remotes in sync

```bash
# After rebasing, update private remote
git push --force-with-lease origin feature

# Sync public with private (after review)
git fetch origin
git push github origin/main:main

# Prune stale refs on all remotes
git fetch --all --prune
```

---

## Rebase Workflows

### Basic rebase

```bash
git rebase main                   # Rebase current branch onto main
git rebase main feature           # Rebase feature onto main
git rebase --onto main A B        # Transplant B (from A) onto main
```

### Interactive rebase

```bash
git rebase -i HEAD~5              # Rewrite last 5 commits
git rebase -i main                # Rewrite all commits since main
```

Interactive commands:
- `pick` - keep commit as-is
- `reword` - edit commit message
- `edit` - pause to amend
- `squash` - merge into previous, combine messages
- `fixup` - merge into previous, discard message
- `drop` - remove commit
- `exec <cmd>` - run command after each commit
- `break` - pause rebase here

### Autosquash workflow

```bash
# Create fixup commits during development
git commit --fixup <sha>
git commit --squash <sha>

# Clean up before merge
git rebase -i --autosquash main
```

### Rebase with testing

```bash
# Run tests after each rebased commit
git rebase -i --exec "make test" main
```

### Rebase control

```bash
git rebase --continue             # After resolving conflicts
git rebase --skip                 # Skip problematic commit
git rebase --abort                # Cancel and restore original state
git rebase --quit                 # Stop but keep current state
git rebase --edit-todo            # Modify remaining todo list
```

### Split a commit

```bash
git rebase -i <commit>^
# Mark the commit as 'edit'
git reset HEAD^                   # Undo commit, keep changes
git add -p                        # Stage first part
git commit -m "Part 1"
git add .                         # Stage rest
git commit -m "Part 2"
git rebase --continue
```

### Rebase vs merge decision

Use rebase when:
- Cleaning up local commits before push
- Keeping linear history on feature branches
- Preparing commits for review

Use merge when:
- Integrating shared/public branches
- Preserving exact history of collaboration
- When branch has been pushed and others depend on it

---

## Stash Operations

### Saving work

```bash
git stash                         # Stash tracked modified files
git stash push -m "description"   # With message
git stash push -u                 # Include untracked files
git stash push -a                 # Include ignored files too
git stash push -p                 # Interactive hunk selection
git stash push --staged           # Stash only staged changes (git 2.35+)
git stash push -- <path>          # Stash specific files
```

### Retrieving stashed work

```bash
git stash pop                     # Apply latest and remove from list
git stash apply                   # Apply latest, keep in list
git stash apply stash@{2}        # Apply specific stash
git stash pop --index             # Restore staged state too
```

### Managing stashes

```bash
git stash list                    # List all stashes
git stash show                    # Show latest stash diff summary
git stash show -p                 # Show latest stash as patch
git stash show stash@{1}         # Show specific stash
git stash drop stash@{0}         # Remove specific stash
git stash clear                   # Remove all stashes
```

### Stash to branch

```bash
git stash branch <name>           # Create branch from stash point, apply, drop
```

### Workflow: pull into dirty tree

```bash
git stash
git pull --rebase
git stash pop
```

### Workflow: test staged changes only

```bash
git stash push --keep-index       # Stash unstaged, keep staged
# run tests on staged changes
git stash pop                     # Restore unstaged
```

---

## Cherry-Pick and Patching

### Cherry-pick

```bash
git cherry-pick <sha>             # Apply single commit
git cherry-pick <sha1> <sha2>     # Apply multiple commits
git cherry-pick A..B              # Apply range (exclusive of A)
git cherry-pick -n <sha>          # Apply without committing
git cherry-pick -x <sha>          # Append "cherry picked from" note
git cherry-pick --edit <sha>      # Edit message before committing
```

### Cherry-pick conflict resolution

```bash
git cherry-pick --continue        # After resolving conflicts
git cherry-pick --skip            # Skip current commit
git cherry-pick --abort           # Cancel entire operation
```

### Revert (safe undo for public branches)

```bash
git revert <sha>                  # Create commit undoing changes
git revert <sha1>..<sha2>         # Revert range
git revert -n <sha>               # Stage revert without committing
git revert --no-commit HEAD~3..   # Revert last 3 commits as one
```

### Apply patches

```bash
git format-patch main             # Generate patch files
git am < patch-file               # Apply patch (with commit)
git apply patch-file              # Apply patch (without commit)
git apply --check patch-file      # Dry-run patch application
```

---

## Reset and Restore

### Reset modes

| Mode | HEAD | Index | Working Tree | Use Case |
|------|------|-------|--------------|----------|
| `--soft` | Moved | Unchanged | Unchanged | Undo commit, keep staged |
| `--mixed` (default) | Moved | Reset | Unchanged | Unstage files |
| `--hard` | Moved | Reset | Reset | Discard everything |
| `--merge` | Moved | Reset | Preserved (if clean) | Abort merge safely |
| `--keep` | Moved | Reset | Preserved (if clean) | Remove commits, keep work |

### Common reset patterns

```bash
# Unstage a file
git reset HEAD -- <file>

# Undo last commit, keep changes staged
git reset --soft HEAD~1

# Undo last commit, unstage changes
git reset HEAD~1

# Discard last 3 commits entirely (DESTRUCTIVE)
git reset --hard HEAD~3

# Abort a merge
git reset --merge ORIG_HEAD

# Move commits to new branch, reset current
git branch topic-branch
git reset --hard HEAD~3
```

### Restore (modern alternative to checkout for files)

```bash
git restore <file>                # Discard working tree changes
git restore --staged <file>       # Unstage file
git restore --source=HEAD~2 <file>  # Restore from specific commit
git restore --staged --worktree <file>  # Unstage and discard changes
```

---

## Safety and Recovery

### Reflog: your safety net

```bash
git reflog                        # Show HEAD movement history
git reflog show <branch>          # Show branch movement history
git reflog show --date=relative   # With relative timestamps
```

### Recovery patterns

```bash
# Recover from accidental reset --hard
git reflog
git reset --hard HEAD@{1}         # Go back one reflog entry

# Recover deleted branch
git reflog
git branch recovered <sha-from-reflog>

# Recover after bad rebase
git reset --hard ORIG_HEAD        # ORIG_HEAD set before rebase

# Find lost commits
git fsck --lost-found             # Find unreachable objects
git log --all --oneline $(git fsck --no-reflogs 2>/dev/null | grep commit | cut -d' ' -f3)
```

### Force push safety

```bash
# NEVER use bare --force on shared branches
# ALWAYS prefer --force-with-lease
git push --force-with-lease origin feature

# Even safer: force-with-lease + force-if-includes
git push --force-with-lease --force-if-includes origin feature

# Preview what would be pushed
git push --dry-run origin feature

# If you must force push, fetch first
git fetch origin
git push --force-with-lease origin feature
```

### Pre-push verification

```bash
# Check what will be pushed
git log origin/main..HEAD         # Commits to be pushed
git diff origin/main..HEAD --stat # Files changed

# Dry run
git push --dry-run origin main
```

### Recovering stashes

```bash
# Find lost stashes after clear
git fsck --unreachable | grep commit | cut -d' ' -f3 | xargs git log --merges --no-walk --grep=WIP
```

### ORIG_HEAD usage

ORIG_HEAD is set before operations that move HEAD significantly:
- `git reset`
- `git merge`
- `git rebase`

```bash
# Undo last merge
git reset --hard ORIG_HEAD

# Undo last rebase
git reset --hard ORIG_HEAD
```

---

## Debugging with Bisect

### Manual bisect

```bash
git bisect start
git bisect bad                    # Current commit is broken
git bisect good v1.0              # This version was working
# Git checks out midpoint
# Test, then mark:
git bisect good                   # or git bisect bad
# Repeat until culprit found
git bisect reset                  # Return to original state
```

### Automated bisect

```bash
# With a test script (exit 0 = good, exit 1 = bad, exit 125 = skip)
git bisect start HEAD v1.0 --
git bisect run ./test-script.sh
git bisect reset
```

### Bisect with build failures

```bash
# test-script.sh:
#!/bin/sh
make || exit 125          # Can't build = skip
./run-tests || exit 1     # Tests fail = bad
exit 0                    # All good
```

### Bisect log and replay

```bash
git bisect log                    # Show bisect history
git bisect log > bisect.log       # Save for replay
git bisect replay bisect.log      # Replay a bisect session
```

---

## Worktree Management

### Create and manage worktrees

```bash
git worktree add <path> <branch>         # Create linked worktree
git worktree add -b <new> <path> <start> # Create with new branch
git worktree add --detach <path> <sha>   # Detached HEAD worktree
git worktree list                        # Show all worktrees
git worktree remove <path>               # Delete worktree
git worktree prune                       # Clean stale metadata
git worktree lock <path>                 # Prevent auto-pruning
git worktree unlock <path>               # Allow pruning again
```

### Practical worktree patterns

```bash
# Emergency hotfix without disrupting current work
git worktree add ../hotfix -b hotfix main
cd ../hotfix
# fix, commit, push
cd ../main-repo
git worktree remove ../hotfix

# Review a PR without switching branches
git fetch origin pull/123/head:pr-123
git worktree add ../review-pr pr-123
cd ../review-pr
# review, test
cd ../main-repo
git worktree remove ../review-pr

# Parallel feature development
git worktree add ../feature-b -b feature-b develop
```

---

## Common Workflow Patterns

### Feature branch workflow

```bash
# Start feature
git switch -c feat/my-feature main
# ... develop ...
git add -p && git commit -m "feat: implement X"

# Keep up to date
git fetch origin
git rebase origin/main

# Push for review
git push -u origin feat/my-feature

# After review, merge
git switch main
git merge --no-ff feat/my-feature
git push origin main
git branch -d feat/my-feature
git push origin --delete feat/my-feature
```

### Squash merge workflow

```bash
# Develop on feature branch with many small commits
git switch main
git merge --squash feat/messy-history
git commit -m "feat: add complete feature X"
```

### Rebase before merge workflow

```bash
git switch feat/my-feature
git rebase -i main                # Clean up commits
git switch main
git merge --ff-only feat/my-feature  # Fast-forward only
```

### Hotfix workflow

```bash
git switch -c fix/critical main
# fix the bug
git commit -m "fix: resolve critical issue"
git push origin fix/critical
# merge to main
git switch main
git merge fix/critical
git push origin main
# tag if needed
git tag -a v1.0.1 -m "Hotfix release"
git push origin v1.0.1
```

### Multi-remote publish workflow (Gitea + GitHub)

```bash
# Daily: push to private
git push origin main

# Publishing: use safety script
bash scripts/publish-to-github.sh

# With tag for PyPI release
bash scripts/publish-to-github.sh --tag v3.0.0

# Manual equivalent (when script is not available):
# 1. Verify no private content
# 2. Push to public
git push github main
git push github --tags
```

### Undo patterns

```bash
# Undo last commit (keep changes)
git reset --soft HEAD~1

# Undo last commit (discard changes) -- DESTRUCTIVE
git reset --hard HEAD~1

# Undo a pushed commit (safe for shared branches)
git revert <sha>

# Undo a merge commit
git revert -m 1 <merge-sha>

# Undo staging
git restore --staged <file>

# Discard working tree changes
git restore <file>

# Undo a rebase
git reset --hard ORIG_HEAD
```

### Clean up workflow

```bash
# Remove untracked files (dry run first)
git clean -nd                     # Preview
git clean -fd                     # Execute (directories too)
git clean -fxd                    # Include ignored files

# Prune remote tracking branches
git fetch --prune
git remote prune origin

# Delete merged branches
git branch --merged main | grep -v main | xargs git branch -d
```

---

## Quick Reference: Dangerous Commands

Commands that can lose data if misused:

| Command | Risk | Safer Alternative |
|---------|------|-------------------|
| `git reset --hard` | Discards all uncommitted work | `git stash` first, or use `--keep` |
| `git push --force` | Overwrites remote history | `git push --force-with-lease` |
| `git clean -fd` | Deletes untracked files permanently | `git clean -nd` (dry run first) |
| `git checkout -- <file>` | Discards working tree changes | `git stash` the file first |
| `git branch -D` | Deletes branch regardless of merge | `git branch -d` (safe delete) |
| `git rebase` (on shared branch) | Rewrites public history | `git merge` instead |

---

## Quick Reference: Refspec Patterns

| Pattern | Meaning |
|---------|---------|
| `main` | Push/fetch local main to/from remote main |
| `main:deploy` | Local main to remote deploy |
| `HEAD:main` | Current branch to remote main |
| `:branch` | Delete remote branch |
| `+main` | Force update (skip fast-forward check) |
| `refs/heads/*:refs/heads/*` | All branches |
| `refs/tags/*:refs/tags/*` | All tags |
