Back to blog

Complete Git guide for freelance developers

October 1, 2024 Dedimarco
git development freelance productivity
Complete Git guide for freelance developers

Git is every developer’s essential tool. But for a freelancer juggling multiple projects, clients, and teams, mastering Git goes far beyond simple git add and git commit. A coherent branch strategy, clear commit conventions, and a workflow adapted to freelance collaboration make the difference between a project that runs smoothly and one that spirals into chaos. Here’s a complete guide based on 16 years of experience.

Branch strategies

Your choice of branch strategy depends on project size, deployment frequency, and the number of contributors.

GitFlow: the classic method

GitFlow, popularized by Vincent Driessen in 2010, uses long-lived branches and a strict hierarchy:

main ─────────────────────────────────────► (production)
  │                                          ▲
  ├── develop ───────────────────────────────┤ (integration)
  │     │          │          │              │
  │     ├── feature/login ──┘              │
  │     ├── feature/api ────┘              │
  │                                          │
  │     └── release/1.0 ────────────────────┘

  └── hotfix/fix-bug ──────────────────────►┘

The branches:

  • main: production code, always stable
  • develop: feature integration
  • feature/*: new feature development
  • release/*: version preparation
  • hotfix/*: urgent production fixes

When to use it: projects with planned release cycles, mobile apps with App Store/Play Store versioning, regulated environments requiring strict deployment control.

GitHub Flow: simplicity

GitHub Flow simplifies the model with a single main branch and short feature branches:

main ─────●─────●─────●─────●──────► (always deployable)
            ▲         ▲
            │         │
       feature/A  feature/B
       (PR + review) (PR + review)

The principle is simple:

  1. Create a branch from main
  2. Work on the feature
  3. Open a Pull Request for review
  4. Merge into main after approval
  5. Deploy immediately

Trunk-based development: expert mode

Trunk-based development pushes the logic even further: ultra-short branches (a few hours to one day maximum) or direct commits to the main branch:

# Ephemeral branch
git checkout -b quick-fix
# Changes...
git commit -am "fix: quick fix"
git push origin quick-fix
# PR, review, merge within the hour

# Or directly on main (for small changes)
git checkout main
# Changes...
git commit -am "docs: update README"
git push origin main

Incomplete features are hidden behind feature flags:

if (featureFlag.isEnabled('new-payment-flow')) {
  // New payment logic
} else {
  // Legacy logic
}

My choice as a freelancer

After years of experience, my recommendation for freelancers is an adapted GitHub Flow:

  • Solo projects: Pure GitHub Flow. A main branch always deployable, short feature branches.
  • Teams of 2-5 people: GitHub Flow with staging environments.
  • Teams > 5 people or planned releases: Lightened GitFlow (without the develop branch if deployments are frequent).

Commit conventions: Conventional Commits

Well-structured commits are essential for maintenance and collaboration:

<type>[optional scope]: <description>

[optional body]

[optional footer]

Types:

  • feat: new feature
  • fix: bug fix
  • docs: documentation
  • style: formatting (no functional impact)
  • refactor: refactoring
  • test: test addition/modification
  • chore: maintenance tasks
  • perf: performance optimization

Examples:

git commit -m "feat(auth): add OAuth2 login with Google"
git commit -m "fix(cart): prevent duplicate items on rapid clicks"
git commit -m "docs: update API documentation for v2 endpoints"
git commit -m "perf(images): implement WebP conversion pipeline"

These conventions allow automatic changelog generation and at-a-glance project history understanding.

Daily best practices

The .gitignore from day one

Every project should start with a proper .gitignore:

# Dependencies
node_modules/
vendor/

# Environment
.env
.env.local
.env.*.local

# Build
dist/
build/

# IDE
.vscode/
.idea/

# OS
.DS_Store
Thumbs.db

# Logs
*.log
npm-debug.log*

Handling merge conflicts

Conflicts are inevitable. Here’s a systematic method:

# Update main
git checkout main && git pull

# Rebase your feature branch onto main
git checkout feature/my-feature
git rebase main

# If conflict occurs, resolve and continue
git add <files>
git rebase --continue

# Or abort the rebase if needed
git rebase --abort

Rebase is preferred over merge for a cleaner, linear history:

# History with merge (less readable)
*   Merge branch 'feature/login' into main
|\
| * feat: add login form
|/
* feat: add auth module

# History with rebase (cleaner)
* feat: add login form
* feat: add auth module

Git aliases to save time

# ~/.gitconfig
[alias]
  st = status -sb
  co = checkout
  br = branch
  cm = commit -m
  lg = log --oneline --graph --all --decorate
  unstage = reset HEAD --
  last = log -1 HEAD --stat
  undo = reset --soft HEAD~1

Freelance collaboration workflows

Case 1: Joining an existing project

# Clone the repo
git clone <url>
cd <project>

# Understand the branch structure
git branch -a

# Create your working branch
git checkout -b freelance/marc-feature main

# Follow existing conventions
git log --oneline -20

Case 2: Managing a project for a client

# Recommended structure
git init
git checkout -b main

# Protect main (on GitHub/GitLab)
# - Require pull request reviews
# - Require status checks
# - No force push

# Branch per task
git checkout -b feature/redesign-homepage

Case 3: Collaborating with in-house developers

# Sync regularly
git fetch origin
git rebase origin/main

# Clear PR with description
gh pr create --title "feat: redesign homepage" \
  --body "## Changes
- New hero section
- Updated navigation
- Mobile responsive layout

## Testing
- [x] Desktop Chrome/FF/Safari
- [x] Mobile iOS/Android"

Complementary tools

Git hooks with Husky

Automate checks before each commit:

# Installation
npm install -D husky
npx husky init
# .husky/pre-commit
npx lint-staged
// package.json
{
  "lint-staged": {
    "*.{js,ts}": ["eslint --fix", "prettier --write"],
    "*.{css,scss}": ["stylelint --fix", "prettier --write"],
    "*.md": ["prettier --write"]
  }
}

Git Bisect to find bugs

# Git bisect finds the commit that introduced a bug
git bisect start
git bisect bad           # Current commit is broken
git bisect good v1.0     # This version worked

# Git automatically checks out intermediate commits
# Test and indicate good/bad
git bisect good          # or git bisect bad

# Repeat until the offending commit is found
git bisect reset         # Return to HEAD

Conclusion

As a freelancer, your Git mastery reflects your professionalism. A clean history, respected conventions, and a workflow adapted to the project context make a difference in collaboration with clients and their teams. Start simple — GitHub Flow with Conventional Commits — and add complexity only when the context demands it.

The best strategy is the one you apply consistently. Document your choices in a CONTRIBUTING.md shared with each team, and don’t hesitate to adjust across projects.