Git Workflow untuk Solo Developer yang Efisien

by Marcus Chen
Git Workflow untuk Solo Developer yang Efisien

Kamu solo developer, kerja sendiri, nggak ada code review, nggak ada PR yang nunggu approval dua hari. Terus ngapain repot-repot bikin git workflow yang proper?

Jawaban pendeknya: karena dua minggu lagi kamu bakal lupa kenapa kamu nulis kode itu, dan git log kamu isinya cuma fix, fix2, fix final, fix final beneran. Itu bukan version control — itu chaos dengan timestamp.

Artikel ini tentang git workflow untuk solo developer yang realistis: nggak over-engineered kayak workflow tim 20 orang, tapi cukup terstruktur biar kamu nggak nangis waktu harus rollback ke versi tiga minggu lalu.

Masalah Nyata: Git Log yang Nggak Bisa Dibaca

Ini contoh git log --oneline yang sering gue lihat di repo solo developer:

a3f1c2e fix
9b2d4f1 update
3e8a7c0 wip
d1f5b2a fix lagi
7c3e9d1 coba
2a8f4e3 final
1b9c5d2 final2

Sekarang coba jawab: commit mana yang ngebreak endpoint /api/users? Kamu nggak bisa jawab tanpa git diff satu-satu.

Bandingkan dengan ini:

a3f1c2e feat(auth): add JWT refresh token endpoint
9b2d4f1 fix(api): handle null user on /api/users response
3e8a7c0 chore: update dependencies, bump express 4.18→4.19
d1f5b2a feat(db): add index on users.email column
7c3e9d1 fix(auth): correct token expiry calculation

Langsung keliatan strukturnya. Ini yang mau kita capai.

Branching Strategy untuk Solo Developer

Kalau kamu kerja sendiri, kamu nggak perlu GitFlow yang ada develop, release, hotfix, feature branch semuanya. Itu overhead yang nggak worth it.

Gue pakai model yang lebih simpel: trunk-based dengan feature branch pendek.

Strukturnya:

  • main — production-ready, selalu bisa di-deploy
  • feat/nama-fitur — branch untuk fitur baru, umurnya maksimal 2–3 hari
  • fix/nama-bug — branch untuk bugfix

Contoh praktisnya:

# Mulai fitur baru
git checkout -b feat/user-authentication

# Kerja, commit, kerja, commit...

# Selesai, merge ke main
git checkout main
git merge --no-ff feat/user-authentication
git branch -d feat/user-authentication

Flag --no-ff itu penting. Tanpanya, git bakal fast-forward dan kamu kehilangan konteks bahwa sekumpulan commit itu bagian dari satu fitur. Dengan --no-ff, ada merge commit yang jelas: "ini satu unit kerja selesai."

Gotcha yang pernah gue kena: jangan biarin feature branch hidup lebih dari 3 hari. Makin lama, makin susah merge-nya karena main udah jalan duluan. Kalau fitur kamu butuh waktu lebih dari itu, pecah jadi sub-fitur yang lebih kecil.

Commit Convention: Pakai Conventional Commits

Ini standar yang worth it buat dipelajari: Conventional Commits. Formatnya:

<type>(<scope>): <description>

[optional body]

[optional footer]

Type yang paling sering dipakai:

  • feat — fitur baru
  • fix — bugfix
  • chore — maintenance, update deps, config
  • docs — perubahan dokumentasi
  • refactor — refactor tanpa perubahan behavior
  • test — tambah atau update test
  • perf — performance improvement

Contoh commit yang bener:

git commit -m "feat(payment): integrate Midtrans payment gateway"
git commit -m "fix(auth): prevent token reuse after logout"
git commit -m "chore: add .env.example for new contributors"
git commit -m "refactor(db): extract query builder to separate module"

Kenapa ini worth it buat solo developer? Karena:

  1. git log kamu jadi dokumentasi otomatis
  2. Kamu bisa generate CHANGELOG otomatis (lebih lanjut di bawah)
  3. Waktu debugging, kamu bisa filter: git log --grep="fix(auth)" langsung ketemu semua commit yang relate ke auth

Setup Commitlint Biar Nggak Lupa Convention

Masalahnya, waktu lagi buru-buru, kamu bakal nulis git commit -m "fix" lagi. Solusinya: enforce convention dengan commitlint + husky.

Install dulu:

npm install --save-dev @commitlint/cli @commitlint/config-conventional husky

Buat config commitlint:

# commitlint.config.js
echo "module.exports = { extends: ['@commitlint/config-conventional'] }" > commitlint.config.js

Setup husky:

npx husky init
echo "npx --no -- commitlint --edit \$1" > .husky/commit-msg

Sekarang kalau kamu coba commit dengan pesan yang nggak sesuai format:

git commit -m "fix aja dulu"
# ⧗   input: fix aja dulu
# ✖   subject may not be empty [subject-empty]
# ✖   type may not be empty [type-empty]
# ✖   found 1 problems, 0 warnings

Git bakal nolak commit-nya. Ini annoying di awal, tapi dua minggu kemudian kamu bakal berterima kasih.

Gotcha: kalau kamu pakai monorepo atau project yang bukan Node.js, kamu perlu workaround lain. Untuk Python project misalnya, kamu bisa pakai pre-commit framework dengan hook conventional-pre-commit.

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/compilerla/conventional-pre-commit
    rev: v3.4.0
    hooks:
      - id: conventional-pre-commit
        stages: [commit-msg]
        args: [feat, fix, chore, docs, refactor, test, perf]

Tagging dan Versioning yang Benar

Solo developer sering skip tagging. Padahal tag itu yang bikin kamu bisa bilang "deploy yang kemarin" dengan tepat, bukan nebak-nebak berdasarkan tanggal.

Pakai semantic versioning: MAJOR.MINOR.PATCH

  • MAJOR — breaking change
  • MINOR — fitur baru, backward compatible
  • PATCH — bugfix
# Tag versi baru
git tag -a v1.2.0 -m "Release v1.2.0: add payment integration"
git push origin v1.2.0

# Lihat semua tag
git tag -l

# Checkout ke versi tertentu
git checkout v1.1.0

Kalau kamu udah pakai Conventional Commits, kamu bisa generate CHANGELOG dan bump version otomatis pakai standard-version atau release-it:

npm install --save-dev release-it

# Tambah ke package.json scripts:
# "release": "release-it"

npm run release
# Tool ini bakal:
# 1. Bump version di package.json
# 2. Generate CHANGELOG.md dari commit history
# 3. Buat git tag
# 4. Push ke remote

Git Alias untuk Workflow Sehari-hari

Ini yang sering dilewatin tapi bikin produktivitas naik lumayan. Setup alias di ~/.gitconfig:

[alias]
    # Log yang enak dibaca
    lg = log --oneline --graph --decorate --all
    
    # Status pendek
    st = status -s
    
    # Lihat diff yang belum di-stage
    d = diff
    
    # Lihat diff yang sudah di-stage
    dc = diff --cached
    
    # Undo commit terakhir tapi keep changes
    undo = reset HEAD~1 --mixed
    
    # Amend commit terakhir tanpa ganti pesan
    oops = commit --amend --no-edit
    
    # Branch cleanup: hapus branch yang sudah di-merge
    cleanup = !git branch --merged | grep -v '\*\|main\|master' | xargs -n 1 git branch -d

Contoh penggunaan:

# Lihat history dengan visual graph
git lg

# Typo di commit terakhir? Tambah file yang ketinggalan?
git add file-yang-ketinggalan.js
git oops  # amend tanpa ganti pesan

# Bersihkan branch yang udah di-merge
git cleanup

Gotcha dengan git oops: jangan pakai ini kalau commit yang mau kamu amend udah di-push ke remote. Itu bakal rewrite history dan bikin masalah. Kalau udah push, buat commit baru aja.

Stash yang Bener: Jangan Cuma git stash

Kamu pasti pernah punya multiple stash dan bingung isinya apa:

git stash list
# stash@{0}: WIP on feat/payment: a3f1c2e feat(auth): ...
# stash@{1}: WIP on main: 9b2d4f1 fix(api): ...
# stash@{2}: WIP on main: 3e8a7c0 chore: ...

Pakai git stash push -m dengan nama yang deskriptif:

# Stash dengan nama
git stash push -m "wip: midtrans webhook handler, belum handle refund case"

# Pop stash spesifik berdasarkan nama
git stash list  # cari index-nya
git stash pop stash@{0}

Kalau kamu mau stash hanya file tertentu:

git stash push -m "wip: experiment dengan redis cache" -- src/cache.js src/config/redis.js

.gitignore yang Sering Kelupaan

Ini bukan tentang .env yang semua orang udah tau. Yang sering kelupaan:

# Editor artifacts
.vscode/settings.json  # keep .vscode/extensions.json kalau mau share recommendations
.idea/
*.swp
*.swo

# OS files
.DS_Store
Thumbs.db

# Debug logs
npm-debug.log*
yarn-debug.log*

# Test coverage
coverage/
.nyc_output/

# Build artifacts yang sering ke-commit nggak sengaja
dist/
build/
*.min.js  # kalau ini generated

# Local override files
docker-compose.override.yml
.env.local

Kalau kamu udah terlanjur commit file yang harusnya di-ignore:

# Hapus dari tracking tapi keep di local
git rm --cached .env
git rm --cached -r dist/

# Commit perubahannya
git commit -m "chore: remove accidentally tracked files from repo"

Yang Gue Lakuin Sekarang

Setup gue saat ini untuk setiap project baru:

  1. Init dengan template — gue punya shell script yang langsung setup commitlint, husky, .gitignore standar, dan release-it config dalam satu command.

  2. Branch protection lokal — walaupun repo pribadi, gue set reminder di calendar tiap Jumat untuk merge semua feature branch yang udah selesai dan cleanup branch yang stale.

  3. Weekly tag — kalau ada progress signifikan minggu itu, gue tag dengan format v0.x.0-alpha.YYYYMMDD. Ini overkill buat beberapa orang, tapi gue pernah kehilangan satu minggu kerja karena nggak bisa identify "versi yang jalan kemarin" dengan tepat.

  4. Git log sebagai standup — karena solo, gue pakai git lg --since="1 week ago" --author="Marcus" sebagai weekly review: ngapain aja minggu ini, apakah fokus atau scatter.

Kalau kamu baru mulai, jangan implement semua sekaligus. Mulai dari Conventional Commits dulu — itu yang paling besar impact-nya. Setelah itu baru tambah commitlint biar enforce otomatis, kemudian tagging, kemudian alias.

Git workflow yang bagus buat solo developer bukan tentang ikutin semua best practice tim enterprise. Ini tentang bikin future-you bisa kerja efisien tanpa harus reverse-engineer keputusan past-you.