Git workflow for website development: best practices from solo to team

An indie developer once broke his blog's styling and overwrote an old backup in a single misstep — he only got the site back because a commit from months earlier let him restore it. His takeaway: "Git's greatest value isn't record-keeping, it's undo." For web development, Git should be there from the first line of code: solo projects need "rollback," while teams shipping a SaaS product need "collaboration." This article walks from solo to team with a workflow that's sufficient without being bloated.

1. Solo Projects: GitHub Flow Is Enough

For a personal site, personal blog, or small tool, skip elaborate processes — GitHub Flow is the one recommendation: a single main branch plus short-lived feature branches.

# 1. Create a feature branch
git checkout -b feature/new-homepage

# 2. Develop on the branch, commit frequently
git add .
git commit -m "feat: redesign homepage hero section"

# 3. Push to remote
git push origin feature/new-homepage

# 4. Open a Pull Request on GitHub
# 5. Self-review, then merge into main
git checkout main
git merge feature/new-homepage

The key habit is one logical change per commit: separate a styling change from a copy change, so a rollback can target "just that styling commit." Solo developers are the most tempted to cut corners, but six months later, a clean git log saves you hours of debugging. One more solo tip: don't let local branches pile up — once a feature is done, merge it into main and delete the old branch. Fewer branches, clearer head.

Commit message convention

Conventional Commits keeps history readable and automatable (many release tools generate changelogs straight from the prefixes):

feat: New feature
fix: Bug fix
docs: Documentation
style: Formatting (no functional change)
refactor: Code restructuring
perf: Performance improvement
test: Testing
chore: Build process or tooling changes

Examples:

  • feat: add user login page
  • fix: correct mobile menu z-index issue
  • perf: optimize image loading with lazy loading

2. Team Collaboration: Pick the Flow by Release Cadence

Git Flow (versioned release projects)

main ────────●─────────────●─────────  (stable releases)
             \             /
develop ──────●───●──●──────●───  (daily development)
                 \    /        \
feature/login    ●──●           feature/payment

Branch naming convention

feature/xxx    — new features
fix/xxx        — bug fixes
hotfix/xxx     — emergency fixes (merge straight to main)
release/xxx    — release preparation

Trade-off advice: continuously deployed SaaS should use GitHub Flow; version-shipped products should use Git Flow. The former chases small, fast steps; the latter suits fixed release windows (e.g., app-store review). Don't blindly adopt full Git Flow with a small team — for three people, a develop branch is often just overhead. One more detail: whichever flow you pick, agree on "who is allowed to merge into protected branches" and write it into the team convention, so there's no permission vacuum.

3. .gitignore: Stop Dirty Files at the Source

# Node
node_modules/
npm-debug.log*
.env

# Build output
dist/
build/
.next/

# IDE
.vscode/
.idea/
*.swp
*.swo

# OS
.DS_Store
Thumbs.db

Files like .env that hold secrets are especially important: once committed to history, deleting them doesn't help (they're still in the log). If it happens, rewrite history with git filter-repo and rotate the keys. Also, commit .gitignore itself into version control, so the whole team stays in sync on ignore rules.

4. CI/CD: Automate Deployment

GitHub Actions example

# .github/workflows/deploy.yml
name: Deploy to Production
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Install dependencies
        run: npm ci
      
      - name: Run tests
        run: npm test
      
      - name: Build
        run: npm run build
      
      - name: Deploy to server
        uses: easingthemes/ssh-deploy@main
        with:
          SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
          SOURCE: "dist/"
          REMOTE_HOST: ${{ secrets.DEPLOY_HOST }}
          REMOTE_USER: ${{ secrets.DEPLOY_USER }}
          TARGET: /var/www/example.com/

The payoff of CI/CD is handing repetitive work to machines: every push runs tests and the build automatically, deploying only when everything is green. Keys live in repo Secrets — never in the yaml. If your project has no automation yet, don't chase a full pipeline — wiring up just "build and run tests automatically on push to main" delivers the biggest bang for the buck.

5. Best-practice checklist

  1. Commit early, commit often — one logical change per commit;
  2. Write meaningful commit messages — so teammates (and future you) understand intent;
  3. Never push directly to main — branch + PR/MR, backed by branch protection (block force-push, require PR approval);
  4. Describe changes in the PR — background, changes, and how it was tested, all required;
  5. Keep branches short-lived — the longer a branch lives, the more merge conflicts;
  6. Code review — even solo, self-reviewing a PR catches silly mistakes, and AI review tools can speed it up.

6. Common Incidents and How to Handle Them

A few classic mishaps and their fixes:

  • Committed the wrong file: if not yet pushed, git reset --soft HEAD~1 undoes the commit but keeps the changes; if already pushed, use git revert <commit> to create an inverse commit — never force-push to rewrite shared history;
  • Merge conflicts: reach for git merge --abort first to return to a clean pre-conflict state, read both sides' changes, then retry — don't patch things together inside the conflict;
  • Deleted a branch by mistake: git reflog recovers the branch pointer — as long as there was a recent commit, the branch is almost always recoverable;
  • Committed a secret: git filter-repo to rewrite history plus immediately rotating the key — both together.

One recommendation for teams: rehearse a "rollback from production incident" drill. On the actual bad day, panic is what causes further mistakes; a rehearsed flow lets you roll back in two minutes instead of thirty.

16IDC Takeaway

For web projects, Git's value comes down to "history tracing" and "safe rollback." Even if you're the only developer, git init from the first file — months from now you'll thank yourself. And the moment your team passes two people, turn on branch protection and PR review: it's the cheapest way to hold the line on code quality. For more website-building practices, see the Website Building Tech category.

Reference: Git official docs https://git-scm.com/doc; Conventional Commits spec https://www.conventionalcommits.org/en/

Related: Docker deployment guide