Git is powerful. It’s also easy to mess up. Here are workflows that keep repositories clean and teams productive.

Solo Workflow

For personal projects, keep it simple:

1
2
3
4
5
6
# Work on main, commit often
git add -A
git commit -m "Add user authentication"

# Push when ready
git push origin main

Use branches for experiments:

1
2
3
4
git checkout -b experiment/new-ui
# work...
git checkout main
git merge experiment/new-ui  # or delete if failed

Feature Branch Workflow

The most common team pattern:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# Start feature from main
git checkout main
git pull origin main
git checkout -b feature/user-profile

# Work and commit
git add -A
git commit -m "Add profile page layout"
git commit -m "Add avatar upload"

# Push branch
git push origin feature/user-profile

# Create PR, get reviews, merge

Keep Branches Updated

1
2
3
4
5
6
7
8
9
# Option 1: Merge main into branch
git checkout feature/user-profile
git fetch origin
git merge origin/main

# Option 2: Rebase (cleaner history)
git checkout feature/user-profile
git fetch origin
git rebase origin/main

Commit Message Convention

tLFyoipnxege(essrc#oe1px2ep3)l:ansahtoirotndiefscnreiepdteido.n

Types:

  • feat: New feature
  • fix: Bug fix
  • docs: Documentation
  • style: Formatting
  • refactor: Code restructure
  • test: Tests
  • chore: Maintenance

Examples:

1
2
3
git commit -m "feat(auth): add password reset flow"
git commit -m "fix(api): handle null response from payment provider"
git commit -m "docs: update API authentication section"

Interactive Rebase

Clean up before merging:

1
2
# Squash last 5 commits
git rebase -i HEAD~5

In the editor:

psspsiqqiqcuucukaakasssahhjhbkcdglm1eh0n2fi1o34723584A69A5dddFAdFidiuxduxssetvecryaroplnmoictodordanoettllirlooenlrlebrug

Result: 2 clean commits instead of 5 messy ones.

Stashing Work

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# Save work without committing
git stash

# List stashes
git stash list

# Apply latest stash
git stash pop

# Apply specific stash
git stash apply stash@{2}

# Stash with message
git stash push -m "WIP: user profile refactor"

# Stash specific files
git stash push -m "partial" src/auth.py

Handling Merge Conflicts

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# When merge fails
git merge feature-branch
# CONFLICT in file.py

# Edit the file, resolve conflicts
# Look for <<<<<<< ======= >>>>>>>

# Mark as resolved
git add file.py
git commit  # Completes the merge

Or abort:

1
git merge --abort

Undoing Things

Undo Last Commit (Keep Changes)

1
git reset --soft HEAD~1

Undo Last Commit (Discard Changes)

1
git reset --hard HEAD~1

Undo Specific Commit (Create New Commit)

1
git revert abc123

Discard Uncommitted Changes

1
2
3
4
5
6
7
8
9
# Single file
git checkout -- file.py

# All files
git checkout -- .

# Or using restore (modern)
git restore file.py
git restore .

Recover Deleted Branch

1
2
3
4
5
# Find the commit
git reflog

# Recreate branch
git checkout -b recovered-branch abc123

Git Aliases

Add to ~/.gitconfig:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
[alias]
    st = status -sb
    co = checkout
    br = branch
    ci = commit
    unstage = reset HEAD --
    last = log -1 HEAD
    lg = log --oneline --graph --decorate -20
    branches = branch -a
    tags = tag -l
    stashes = stash list
    amend = commit --amend --no-edit
    undo = reset --soft HEAD~1
    discard = checkout --
    wip = !git add -A && git commit -m 'WIP'
    publish = !git push -u origin $(git branch --show-current)

Usage:

1
2
3
4
5
git st          # Short status
git lg          # Pretty log
git amend       # Amend without changing message
git undo        # Undo last commit
git publish     # Push and set upstream

Git Hooks

Automate checks before commits:

1
2
3
4
5
6
7
8
9
# .git/hooks/pre-commit
#!/bin/bash
# Run linter
npm run lint || exit 1

# Run tests
npm test || exit 1

echo "Pre-commit checks passed"

Make executable:

1
chmod +x .git/hooks/pre-commit

Use Husky for team-shared hooks:

1
2
3
npm install husky --save-dev
npx husky install
npx husky add .husky/pre-commit "npm run lint"

Gitignore Patterns

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# Dependencies
node_modules/
vendor/
.venv/

# Build output
dist/
build/
*.pyc
__pycache__/

# Environment
.env
.env.local
*.local

# IDE
.idea/
.vscode/
*.swp

# OS
.DS_Store
Thumbs.db

# Logs
*.log
logs/

# Secrets (never commit these)
*.pem
*.key
secrets/

Global gitignore:

1
git config --global core.excludesfile ~/.gitignore_global

Working with Remotes

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# List remotes
git remote -v

# Add remote
git remote add upstream https://github.com/original/repo.git

# Fetch from upstream
git fetch upstream

# Merge upstream changes
git merge upstream/main

# Change remote URL
git remote set-url origin git@github.com:user/repo.git

Cherry-Pick

Apply specific commits to another branch:

1
2
3
4
5
6
7
8
git checkout main
git cherry-pick abc123

# Multiple commits
git cherry-pick abc123 def456 ghi789

# Range of commits
git cherry-pick abc123..ghi789

Bisect

Find the commit that introduced a bug:

1
2
3
4
5
6
7
8
9
git bisect start
git bisect bad              # Current commit is broken
git bisect good v1.0.0      # This version worked

# Git checks out commits, you test each one
git bisect good  # or bad

# Eventually finds the culprit
git bisect reset  # Return to normal

Tags

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# List tags
git tag

# Create annotated tag
git tag -a v1.0.0 -m "Release version 1.0.0"

# Create lightweight tag
git tag v1.0.0

# Push tags
git push origin v1.0.0
git push origin --tags

# Delete tag
git tag -d v1.0.0
git push origin --delete v1.0.0

Worktrees

Work on multiple branches simultaneously:

1
2
3
4
5
6
7
8
9
# Create worktree for another branch
git worktree add ../project-hotfix hotfix-branch

# Work in separate directory
cd ../project-hotfix
# make changes, commit, push

# Remove when done
git worktree remove ../project-hotfix

Quick Reference

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# Start
git clone URL                 # Clone repo
git init                      # New repo

# Daily
git status                    # What's changed
git add -A                    # Stage all
git commit -m "message"       # Commit
git push                      # Push

# Branches
git checkout -b name          # Create branch
git checkout main             # Switch
git merge branch              # Merge
git branch -d name            # Delete

# Sync
git fetch                     # Get remote changes
git pull                      # Fetch + merge
git push                      # Send changes

# History
git log --oneline             # Short log
git diff                      # Show changes
git blame file                # Who changed what

# Fix
git reset --soft HEAD~1       # Undo commit
git stash                     # Save for later
git checkout -- file          # Discard changes

Good git habits prevent disasters. Learn the patterns, save yourself hours of recovery.