Working solo doesn't mean you should skip good git practices. Here's a workflow that keeps you productive without ceremony.

The Simple Rule

Commit early, commit often, push immediately.

Solo projects don't need complex branching strategies. What they need is:

  • A clean history you can navigate
  • The ability to undo mistakes
  • Your work backed up remotely

When to Branch

Branch when you're:

  • Experimenting with something risky
  • Refactoring that might break things
  • Working on a feature you might abandon

Don't branch for:

  • Small fixes or updates
  • Content changes (blog posts, docs)
  • Anything you'll merge within the hour
# For experiments
git checkout -b experiment/new-caching
 
# For features
git checkout -b feat/user-auth
 
# When done, merge and clean up
git checkout main
git merge feat/user-auth
git branch -d feat/user-auth

Commit Messages That Help

Future you will read these. Make them useful:

# Good - says what changed and why
git commit -m "Add rate limiting to API endpoints"
git commit -m "Fix memory leak in connection pool"
git commit -m "Refactor auth to use JWT instead of sessions"
 
# Bad - says nothing useful
git commit -m "Update"
git commit -m "Fix bug"
git commit -m "WIP"

Format: imperative mood, present tense. "Add feature" not "Added feature."

The Atomic Commit

Each commit should be one logical change:

# Good - separate concerns
git add src/auth.py
git commit -m "Add password hashing utility"
 
git add src/routes/login.py
git commit -m "Implement login endpoint"
 
# Bad - mixing unrelated changes
git add .
git commit -m "Add auth and fix CSS and update readme"

Push After Every Commit

No reason to let commits sit locally:

git commit -m "Add feature"
git push  # Do this immediately

Benefits:

  • Backup in case your machine dies
  • Can access from anywhere
  • Triggers CI/CD right away

Useful Aliases

Add to your .gitconfig:

[alias]
    s = status -sb
    c = commit -m
    p = push
    l = log --oneline -20
    d = diff
    co = checkout
    undo = reset HEAD~1 --soft

Now you can:

git s          # Quick status
git c "msg"    # Commit with message
git p          # Push
git undo       # Undo last commit (keep changes)

Handling Mistakes

Undo last commit (keep changes):

git reset HEAD~1 --soft

Amend last commit:

git add forgotten-file.py
git commit --amend --no-edit

Discard uncommitted changes:

git checkout -- file.py  # Single file
git checkout -- .        # All files

Already pushed? Force push (solo only!):

git push --force-with-lease

The .gitignore Essentials

Start every project with:

# Environment
.env
.env.local
venv/
node_modules/
 
# IDE
.idea/
.vscode/
*.swp
 
# OS
.DS_Store
Thumbs.db
 
# Build
dist/
build/
*.pyc
__pycache__/
 
# Logs
*.log
logs/

Daily Routine

  1. git pull before starting work
  2. Work in small chunks
  3. Commit each logical piece
  4. Push when done (or more often)
  5. End day with clean working directory

When to Get Fancy

Consider a more structured workflow when:

  • Someone else might contribute
  • You need code review (even self-review)
  • Releases need to be tracked
  • CI/CD requires specific branches

Until then, keep it simple. The best git workflow is one you actually follow.

React to this post: