DEV Community

Alex Chen
Alex Chen

Posted on

The Git Workflow That Actually Works for Solo Developers (2026)

The Git Workflow That Actually Works for Solo Developers (2026)

I've tried Git Flow, GitHub Flow, trunk-based development. Here's what I actually use for my solo projects.

The Problem with Most Git Workflows

Git Flow:         17 branches, 5 merge targets, needs a diagram to explain
GitHub Flow:       Simple but vague on details
Trunk-Based:      Great for teams with CI/CD, overkill for solo
What I need:      Something simple, safe, and works alone
Enter fullscreen mode Exit fullscreen mode

My Workflow: "Practical Branch"

main ──────────────────────────────→ production, always deployable
  ↑                                   (merge only via PR)
  │
  ├── feat/auth-login ──→ PR → merge  (feature branch)
  │
  ├── fix/header-bug ────→ PR → merge  (bugfix branch)
  │
  └── chore/update-deps ─→ PR → merge  (maintenance)
Enter fullscreen mode Exit fullscreen mode

Rules

Rule Why
main is always deployable Never push broken code to main
All changes via Pull Request Self-review before merging
Commit often, push when ready Small commits = easy to debug
One feature per branch Keep changes focused
Delete branch after merge Keep workspace clean

Branch Naming Convention

# Features
feat/user-authentication
feat/payment-integration
feat/dark-mode-toggle

# Bug fixes
fix/login-redirect-loop
fix/memory-leak-in-parser
fix/css-mobile-overflow

# Chore/Maintenance
chore/update-dependencies
chore/configure-linter
docs/api-endpoint-changes

# Hotfix (rare, for production emergencies)
hotfix/critical-security-patch
Enter fullscreen mode Exit fullscreen mode

My Commit Message Format

<type>(<scope>): <subject>

<body if needed>

Fixes #<issue-number>

Signed-off-by: Your Name <email>
Enter fullscreen mode Exit fullscreen mode

Types I Use

Type When
feat New feature or capability
fix Bug fix
docs Documentation only
style Formatting, no logic change
refactor Restructuring, same behavior
perf Performance improvement
test Adding/updating tests
chore Dependencies, config, tooling

Real Examples

feat(auth): add OAuth2 Google login flow

Implement Google OAuth2 using passport.js.
Users can now sign in with their Google account.
Redirects to dashboard on success.

Closes #42

Signed-off-by: Alex Chen <contact@example.com>

---

fix(api): handle empty response from external service

The weather API sometimes returns empty body.
Added null check and fallback to cached data.

Fixes #87

Signed-off-by: Alex Chen <contact@example.com>

---

perf(db): add index on users.email column

Queries on login endpoint were taking 200ms+.
After index: 3ms. 67x improvement.

Signed-off-by: Alex Chen <contact@example.com>
Enter fullscreen mode Exit fullscreen mode

Pre-Push Checklist

Before pushing any code:

#!/bin/bash
# pre-push-check.sh — run this before every push

echo "🔍 Running pre-push checks..."

# 1. No committed secrets?
if git diff --cached --name-only | grep -qE '\.env$|credentials|secret|\.pem'; then
  echo "❌ Possible secret file staged!"
  exit 1
fi

# 2. Code compiles/runs?
npm test -- --test-reporter dot 2>/dev/null || {
  echo "❌ Tests failing!"
  exit 1
}

# 3. No console.log left?
if git diff --cached | grep -q 'console\.(log|debug)'; then
  echo "⚠️  Found console.log in staged changes"
fi

# 4. Branch name is valid?
BRANCH=$(git branch --show-current)
if ! echo "$BRANCH" | grep -qE '^(feat|fix|docs|style|refactor|perf|test|chore|hotfix)/'; then
  echo "⚠️  Branch name doesn't follow convention: $BRANCH"
fi

# 5. Working tree clean?
if [ -n "$(git status --porcelain)" ]; then
  echo "⚠️  Uncommitted changes in working tree"
fi

echo "✅ Pre-push checks passed"
Enter fullscreen mode Exit fullscreen mode

Hook it up:

chmod +x pre-push-check.sh
echo './pre-push-check.sh' > .git/hooks/pre-push
chmod +x .git/hooks/pre-push
Enter fullscreen mode Exit fullscreen mode

Useful Git Aliases

# Add these to ~/.gitconfig

[alias]
    # Status & log
    s = status -sb
    l = log --oneline --graph --decorate -20
    ll = log --stat
    recent = log --since='3 days ago' --oneline

    # Diff
    d = diff
    ds = diff --staged
    dw = diff --word-diff

    # Branch & checkout
    b = branch -va
    co = checkout
    cob = checkout -b

    # Commit
    c = commit
    ca = commit -a
    amend = commit --amend --no-edit
    undo = reset HEAD~1 --mixed

    # Push & pull
    p = push
    pf = push --force-with-lease
    pl = pull --rebase

    # Stash
    save = stash push -m
    pop = stash pop
    list = stash list

    # Quick operations
    unstage = reset HEAD
    discard = checkout --
    ignore = update-index --assume-unchanged
Enter fullscreen mode Exit fullscreen mode

Now you can type:

git s          # instead of git status -sb
git l          # pretty log graph
git cob feat/new-feature  # create & checkout new branch
git pf         # force push (safe version)
Enter fullscreen mode Exit fullscreen mode

Handling Common Situations

"I messed up the last commit"

# Add forgotten file to last commit
git add forgotten-file.js
git amend

# Or change the message
git commit --amend -m "new message"
Enter fullscreen mode Exit fullscreen mode

"I need to split a commit"

git rebase -i HEAD~2
# Change 'pick' to 'edit' on the commit you want to split
# Then:
git reset HEAD~
# Make first commit
git add <part1>
git commit -m "first part"
# Make second commit
git add <part2>
git commit -m "second part"
git rebase --continue
Enter fullscreen mode Exit fullscreen mode

"I pushed to wrong branch"

# Undo the push (safe version)
git push --force-with-lease origin wrong-branch

# Push to correct branch
git push origin correct-branch
Enter fullscreen mode Exit fullscreen mode

"I need to update my fork"

# Add upstream if not already done
git remote add upstream https://github.com/original/repo.git

# Fetch and merge latest
git fetch upstream
git checkout main
git merge upstream/main
git push origin main
Enter fullscreen mode Exit fullscreen mode

My .gitconfig

[user]
    name = Alex Chen
    email = contact@agentvote.cc

[core]
    editor = nano
    autocrlf = input

[init]
    defaultBranch = main

[push]
    autoSetupRemote = true

[pull]
    rebase = false

[merge]
    conflictstyle = zdiff3

[color]
    ui = auto

[help]
    autocorrect = 0
Enter fullscreen mode Exit fullscreen mode

What About Tags and Releases?

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

# List tags
git tag -l --sort=-v:refname

# Show tag details
git show v1.0.0
Enter fullscreen mode Exit fullscreen mode

I use semantic versioning (MAJOR.MINOR.PATCH):

  • MAJOR: Breaking changes
  • MINOR: New features, backward compatible
  • PATCH: Bug fixes

What's your Git workflow? Do you stick to a formal one or keep it casual?

Follow @armorbreak for more practical dev workflows.

Top comments (0)