Kodeloka
  1. Kodeloka
  2. Kelas Git & CI/CD
  3. Materi

Git Workflow · Modul 6 dari 20

Git Tingkat Lanjut - Stash, Worktree, Submodule & Hooks

Perkakas Git yang jarang diajarkan tapi sangat menolong: menyimpan pekerjaan sementara, membuka beberapa branch sekaligus, mengelola repositori bersarang, dan otomatisasi lewat hooks.

1. Stash — Menyimpan Pekerjaan Sementara

# Simpan perubahan dan bersihkan working directory
git stash push -m "eksperimen tata letak keranjang"

# Sertakan berkas yang belum dilacak Git
git stash push -u -m "termasuk berkas baru"

# Simpan hanya berkas tertentu
git stash push -m "hanya css" src/gaya.css

git stash list
# stash@{0}: On fitur: eksperimen tata letak keranjang
# stash@{1}: On main: perbaikan cepat

git stash show -p stash@{0}    # lihat isinya

git stash pop                  # terapkan dan HAPUS dari daftar
git stash apply stash@{1}      # terapkan tapi TETAP simpan
git stash drop stash@{0}
git stash clear                # hapus semua -- hati-hati

# Membuat branch langsung dari stash
git stash branch fitur/eksperimen stash@{0}
⚠️ Stash mudah terlupakan

Stash tidak muncul di git status maupun git log. Pekerjaan yang di-stash berbulan-bulan lalu sering terlupakan sepenuhnya. Selalu beri pesan yang jelas dengan -m, dan untuk pekerjaan yang serius lebih baik buat branch daripada mengandalkan stash.

2. Worktree — Beberapa Branch Sekaligus

Masalah klasik: Anda sedang di tengah pekerjaan, lalu ada bug produksi yang harus segera diperbaiki. Alih-alih stash lalu berpindah branch, buka saja direktori kerja kedua.

# Buat direktori kerja baru untuk branch hotfix
git worktree add ../proyek-hotfix -b hotfix/pembayaran-gagal

# Sekarang ada dua direktori dari SATU repositori:
#   ~/proyek          -> branch fitur/keranjang
#   ~/proyek-hotfix   -> branch hotfix/pembayaran-gagal

git worktree list
git worktree remove ../proyek-hotfix
git worktree prune            # bersihkan catatan yang sudah usang
📌 Kenapa worktree lebih baik daripada clone kedua

Semua worktree berbagi satu direktori .git yang sama, sehingga tidak ada objek yang digandakan dan tidak perlu fetch dua kali. Ini juga sangat berguna saat perlu membandingkan dua versi berdampingan, atau menjalankan uji panjang di satu branch sambil terus bekerja di branch lain.

3. Submodule — Repositori di Dalam Repositori

git submodule add https://github.com/org/pustaka-bersama.git vendor/pustaka

# Meng-clone proyek yang punya submodule
git clone --recurse-submodules https://github.com/org/proyek.git

# Bila terlanjur clone biasa
git submodule update --init --recursive

# Memperbarui submodule ke commit terbaru upstream
git submodule update --remote vendor/pustaka
git add vendor/pustaka
git commit -m "chore: naikkan versi pustaka-bersama"

git submodule status
🚫 Submodule adalah sumber frustrasi yang terkenal

Repositori induk hanya mencatat satu hash commit dari submodule, bukan branch. Akibatnya: orang lupa --recurse-submodules saat clone dan mendapat direktori kosong; submodule sering berada dalam keadaan detached HEAD; dan perubahan di submodule harus di-commit dan dipush secara terpisah sebelum commit di repositori induk, kalau tidak rekan tim akan mendapat referensi ke commit yang tidak ada.

Alternatif yang biasanya lebih baik: publikasikan pustaka bersama sebagai paket berversi (npm, Go module, PyPI) dan pakai manajer dependensi biasa. Pertimbangkan submodule hanya bila Anda benar-benar butuh menyematkan repositori pada commit tertentu.

4. Subtree — Alternatif yang Lebih Ramah

# Menyalin isi repositori lain ke sebuah direktori
git subtree add --prefix=vendor/pustaka \
  https://github.com/org/pustaka-bersama.git main --squash

# Menarik pembaruan
git subtree pull --prefix=vendor/pustaka \
  https://github.com/org/pustaka-bersama.git main --squash

Berbeda dari submodule, isi subtree benar-benar berada di dalam repositori Anda. Orang yang meng-clone tidak perlu tahu apa pun tentang subtree — semuanya langsung ada.

5. Hooks — Otomatisasi pada Peristiwa Git

HookKapan berjalanKegunaan umum
pre-commitSebelum commit dibuatLint, format, pindai rahasia
commit-msgSetelah pesan ditulisValidasi format Conventional Commits
pre-pushSebelum pushJalankan unit test
post-mergeSetelah mergeJalankan npm install bila lockfile berubah
pre-receiveDi server, sebelum menerimaTolak push yang melanggar kebijakan
.git/hooks/pre-commit
#!/bin/sh
set -e

# Tolak commit yang mengandung penanda konflik
if git diff --cached | grep -q "^+<<<<<<<"; then
  echo "❌ Ada penanda konflik yang belum dibereskan."
  exit 1
fi

# Tolak commit yang mengandung debugger
if git diff --cached --name-only | grep -E '\.(js|ts)$' | xargs -r grep -l "debugger"; then
  echo "❌ Hapus dulu pernyataan debugger."
  exit 1
fi

npm run lint
echo "✅ Pemeriksaan pre-commit lolos."
⚠️ Hook di .git/hooks tidak ikut ter-clone

Direktori .git bersifat lokal, sehingga hook yang Anda buat di sana tidak akan dimiliki rekan tim. Agar hook berlaku untuk semua orang, simpan skripnya di dalam repositori dan arahkan Git ke sana:

git config core.hooksPath .githooks

Atau pakai alat pengelola seperti pre-commit (Python), husky + lint-staged (Node.js), atau lefthook yang memasang hook otomatis saat instalasi dependensi.

🚫 Hook lokal bukan mekanisme keamanan

Siapa pun bisa melewati hook dengan git commit --no-verify. Hook adalah alat bantu kenyamanan, bukan penegakan aturan. Aturan yang benar-benar wajib harus ditegakkan di pipeline CI dan branch protection di sisi server, yang tidak bisa dilewati siapa pun.

6. Menjaga Rahasia Tidak Masuk Repositori

.gitignore
.env
.env.*
!.env.example
*.pem
*.key
node_modules/
dist/
__pycache__/
.DS_Store
# Berkas terlanjur dilacak padahal sudah masuk .gitignore?
git rm --cached .env
git commit -m "chore: berhenti melacak berkas .env"

# Memeriksa mengapa sebuah berkas diabaikan
git check-ignore -v config/rahasia.json
🚫 Rahasia yang terlanjur dipush harus dianggap bocor

Menghapusnya di commit berikutnya tidak cukup — nilainya tetap ada di riwayat dan bisa dibaca siapa pun. Langkah yang benar, berurutan: (1) segera cabut dan ganti kredensial tersebut — ini yang paling penting dan tidak boleh ditunda; (2) baru bersihkan riwayat dengan git filter-repo atau BFG Repo-Cleaner; (3) koordinasikan dengan tim karena riwayat akan ditulis ulang.