Skip to content

Git Workflow

Halaman Code Repository menjelaskan penamaan branch. Halaman ini menjelaskan branch itu dibuat dari mana, dan bagaimana pekerjaannya berpindah dari branch tersebut ke branch-branch permanen.

Model branch mana yang dipakai sebuah repository

Ini bukan pilihan. Modelnya mengikuti jumlah environment tempat project itu di-deploy.

Hampir semua pekerjaan kita adalah pekerjaan klien, di-deploy ke lebih dari satu environment, dan tiap tahapnya harus disetujui dulu sebelum perubahannya lanjut. Repository seperti itu memakai branch per environment, dan sisa halaman ini ditulis untuk mereka.

Konvensi

  • Repository yang di-deploy ke lebih dari satu environment memakai branch per environment: satu branch permanen untuk tiap environment, dan tidak ada commit di satu pun branch tersebut.
  • Repository dengan hanya satu environment — tool internal, shared library, situs dokumentasi — memakai satu branch permanen saja. Lihat bagian terakhir di halaman ini.
  • README wajib menyebutkan yang mana dipakai repository tersebut. Developer tidak boleh disuruh menebak sendiri dari daftar branch.
  • Jangan mencampur keduanya dalam satu repository.
  • Repository yang sudah ada tetap bekerja seperti sekarang sampai dipindahkan secara sengaja. Standar ini berlaku untuk semua repository baru, dan untuk repository lama sejak hari ia dipindahkan.

Mulai mengerjakan work item

Titik awal sebuah branch menentukan isi Pull Request-nya. Memulai dari branch yang salah adalah penyebab paling sering Pull Request jadi penuh pekerjaan orang lain, dan memastikannya di awal tidak makan biaya apa pun, sedangkan memperbaikinya belakangan mahal.

Buat branch dari branch permanen yang paling stabil di project tersebut. Itu berarti branch production kalau project-nya punya, kalau tidak ya branch kerjanya. Semua branch permanen lain sudah memuat isi branch itu, jadi branch yang dibuat dari sana bisa di-merge dengan bersih ke branch permanen mana pun, dan hanya membawa commit milikmu sendiri.

Buat branch itu sebelum kamu mengubah file yang pertama, bukan nanti waktu sudah siap commit. File yang diubah selagi branch permanen sedang aktif berarti diubah di atas basis yang nanti tidak dimiliki branch-mu: branch kerja memuat pekerjaan yang belum dirilis, jadi perubahanmu bisa berperilaku lain begitu dipindah ke basis yang benar — atau terpasang mulus sambil diam-diam ikut membawa baris yang belum dirilis. Selain itu pekerjaanmu jadi hanya berjarak satu git commit dari mendarat di branch permanen.

Konvensi

  • Buat branch sebelum edit yang pertama, bukan sebelum commit yang pertama. Jangan ada perubahan apa pun di working tree selagi branch permanen yang sedang aktif.
  • Lakukan fetch dulu, lalu buat branch dari branch remote, bukan dari apa pun yang sedang aktif di lokal:
git fetch origin
git switch -c feat/PROJ-123-multi-shift-support origin/main
  • Jangan membuat branch dari branch kerja kalau project-nya memakai branch per environment. Branch-mu akan ikut membawa pekerjaan yang belum dirilis, dan waktu nanti di-merge ke production, pekerjaan yang belum dirilis itu ikut terbawa.
  • Jangan membuat branch dari salinan lokal yang sudah tertinggal. Pull Request-nya akan menampilkan commit orang lain seolah bagian dari perubahanmu.
  • Tulis ID work item di nama branch, mengikuti halaman Code Repository.
  • Kalau kamu terlanjur mulai mengedit di branch permanen, pindahkan perubahannya, jangan di-commit di tempatnya:
git stash push -u
git switch -c fix/PROJ-123-fractional-price origin/main
git stash pop
  • Setelah dipindah, jalankan lagi build dan test-nya. Basisnya bukan basis yang kamu pakai waktu mengedit, jadi hasil hijau sebelumnya tidak membuktikan apa-apa.

Apa itu target branch

Target adalah branch tujuan sebuah Pull Request di-merge. Target bukan tempat perubahan itu berakhir pada akhirnya.

Satu work item biasanya punya lebih dari satu target selama hidupnya. Branch yang sama di-merge ke masing-masing target, satu per satu, seiring status work item-nya berubah:

Status work itemYang baru saja terjadiBranch di-merge ke
Ready for testingdeveloper sudah selesai menulis kodenyakeduanya — branch kerja dan branch testing, di-merge bersamaan tepat sebelum status-nya dipindahkan
TestingQA sedang memeriksanya di shared development environment
Testing failedQA menemukan masalah, jadi kembali ke In progress
Ready for deploymenttesting lolosbranch production
Donesudah di-deploy dan live di production

Done berarti sudah di-deploy ke production, bukan selesai menulis kode. Yang menandakan kodenya sudah selesai dan sudah masuk ke branch kerja adalah perpindahan work item ke Ready for testing. Nama status berbeda-beda tiap project, tapi bentuk alurnya tidak.

Konvensi

  • Satu work item memakai satu branch, dan branch itu di-merge ke tiap target secara bergiliran. Jangan membuat branch kedua untuk work item yang sama.
  • Satu Pull Request untuk tiap target, dibuka saat work item-nya sampai di status tersebut. Jadi satu branch bisa punya beberapa Pull Request selama hidupnya, pada waktu yang berbeda-beda.
  • Karena selalu branch yang sama, perubahannya memakai commit ID yang sama di semua branch yang dicapainya. Itulah yang membuat perintah berikut memberi jawaban yang benar:
git branch -a --contains <commit>
  • Jangan me-merge satu branch permanen ke branch permanen lain. Kenaikan selalu berupa branch work item yang di-merge ke sebuah target. Me-merge branch kerja ke branch testing akan menyeret semua work item yang belum disetujui sekaligus, dan itu justru yang ingin dicegah oleh status-status tadi.
  • Work item yang di-reopen setelah Done memakai branch baru. Branch lamanya sudah sampai production dan sudah dihapus.
  • Branch kerja dan branch testing di-merge bersamaan, tepat sebelum work item-nya dipindah ke Ready for testing. Di sebagian besar project kita, isi keduanya sama dan yang berbeda hanya tempat deploy-nya — QA internal memakai yang satu, klien memakai yang lain. Keduanya dites paralel, bukan berurutan, jadi branch testing bukan tahap persetujuan. Satu-satunya gerbang adalah yang sebelum production.
  • Kecuali kalau klien butuh environment yang stabil. Saat klien sedang melakukan acceptance testing resmi, work item setengah jadi yang masuk di tengah pengujian membuat hasil tes mereka tidak bisa dipercaya. Dalam keadaan itu, tahan dulu merge ke branch testing, dan tulis di work item-nya supaya tidak ada yang me-merge karena kebiasaan.
  • Pull Request-nya di-merge sendiri oleh assignee work item tersebut, untuk branch kerja dan branch testing. Merge commit dibuat atas nama orang yang menjalankan merge-nya, jadi cara ini membuat namanya melekat di seluruh pekerjaannya, bukan hanya di commit perubahannya. Untuk itu dia butuh akses write di repository tersebut.
  • Pull Request ke production di-merge oleh orang yang bertanggung jawab atas rilis, bukan oleh assignee-nya. Merge itu adalah rilisnya, dan itulah yang dijaga oleh persetujuan klien.
  • Pull Request yang dibuka oleh satu orang lalu di-merge oleh orang lain itu wajar di sini. Jangan dianggap kesalahan yang perlu diperbaiki.

Pekerjaan yang bergantung pada sesuatu yang belum ada di production

Ini pengecualian dari aturan membuat branch dari branch production. Kadang sebuah fix atau fitur dibangun di atas work item lain yang masih ada di branch kerja dan belum dirilis.

Konvensi

  • Kalau pekerjaanmu butuh perubahan yang belum ada di production, buat branch-mu dari branch work item yang kamu butuhkan itu, bukan dari branch production. Membangunnya di atas kode production yang belum memuat perubahan itu memang tidak akan jalan.
  • Dua work item tersebut jadi tidak bisa naik sendiri-sendiri lagi. Naikkan bersama-sama, dan dahulukan work item yang kamu butuhkan.
  • Tulis hal ini di work item-nya, supaya orang yang menyetujui kenaikannya tahu keduanya berjalan sepasang.
  • Sebisa mungkin hindari keadaan ini. Kalau dua pekerjaan memang seketat itu keterikatannya, biasanya lebih baik dijadikan satu work item saja.

Satu work item, satu branch, satu commit

Commit yang mendarat di branch permanen adalah satuan yang dipakai semua proses berikutnya: di-review, dinaikkan, ditelusuri, dan dibatalkan sebagai satu kesatuan. Itu hanya jalan kalau satu work item berarti satu commit.

Konvensi

  • Usahakan satu work item menghasilkan satu commit, dan squash branch-nya jadi satu commit sebelum push pertama. Hanya di saat itu squash boleh dilakukan, karena mengubah branch yang sudah di-push memang dilarang.
  • Merge tiap Pull Request dengan merge biasa. Jangan pernah pakai "Squash and merge". Squash membuat commit baru di branch target yang tidak ada di branch kerja. Target berikutnya lalu me-merge commit asli dari branch tersebut, sehingga perubahan yang sama berakhir dengan dua commit ID berbeda — persis masalah yang ingin dihindari dengan memakai satu branch.
  • Commit yang ditambahkan setelah merge pertama tetap jadi commit tersendiri. Pekerjaan yang kembali dari testing itu wajar, dan tidak sepadan melanggar aturan di atas hanya demi memaksa work item-nya kembali jadi satu commit. Dua commit dengan ID yang sama di semua branch lebih baik daripada satu commit dengan ID berbeda-beda di tiap branch.
  • ID work item ditulis di nama branch dan di commit subject, supaya perubahannya bisa dicari lagi nanti:
git log --all --oneline --grep "PROJ-123"
  • Jangan menggabungkan dua work item dalam satu branch. Setelah itu keduanya tidak bisa lagi di-review, dinaikkan, atau dibatalkan secara terpisah.

Mengerjakan beberapa work item sekaligus

Sebuah branch hidup sampai sampai di production, jadi biasanya ada beberapa branch terbuka pada waktu yang sama. Itu bukan berarti beberapa branch sedang dikerjakan bersamaan — branch yang sedang menunggu testing atau persetujuan tidak butuh working copy sama sekali. Yang butuh hanya branch yang sedang ditulis.

Konvensi

  • Sebisa mungkin selesaikan satu work item dulu sebelum mulai yang berikutnya di repository yang sama. Mengerjakan beberapa repository sekaligus tidak ada biayanya. Yang mahal adalah dua work item di satu repository.
  • Satu working copy hanya bisa berada di satu branch, dan berpindah branch mengganggu apa pun yang ada di working copy itu. Jadi kalau dua work item memang harus terbuka bersamaan di satu repository, tambahkan git worktree untuk yang kedua, jangan berganti branch:
git worktree add ../myrepo-PROJ-123 feat/PROJ-123-multi-shift-support
  • Jangan menjalankan git switch di dalam sebuah worktree. Kalau butuh branch lain, buat worktree lain.
  • Git menolak meng-checkout branch yang sama di dua worktree. Itu pengaman, bukan masalah.
  • Hapus worktree-nya begitu Pull Request pertama di-merge — bukan menunggu work item-nya sampai di production:
git worktree remove ../myrepo-PROJ-123

Branch-nya tetap ada di remote, dan Pull Request berikutnya ke target lain dibuka lewat antarmuka web, yang tidak butuh salinan lokal. Branch yang berumur panjang tidak butuh worktree yang berumur panjang.

  • Hitung dulu biayanya sebelum menambah worktree. Untuk aplikasi web, working copy kedua berarti satu sistem berjalan lagi, bukan sekadar tambahan file: port atau virtual host sendiri, dependency ter-install sendiri, dan sering kali database sendiri.
  • Simpan setelan khusus tiap worktree di file yang diabaikan repository, misalnya .env, yang dibaca relatif terhadap direktori worktree itu sendiri. Dengan begitu tiap worktree menunjuk ke database dan alamatnya sendiri tanpa mengubah satu pun file yang di-track.
  • Database lokal baru boleh dipakai bersama kalau tidak ada hal khusus environment yang tersimpan di dalamnya. Sebagian aplikasi menyimpan base URL-nya sendiri di tabel setting, lalu nama session cookie dan penentuan routing dibentuk dari situ. Dengan satu database bersama, semua worktree membaca alamat yang sama, dan login serta routing rusak di semua worktree kecuali satu. Aplikasi seperti itu butuh salinan database untuk tiap worktree, dengan baris alamatnya diisi URL worktree tersebut.
  • Sekalipun database-nya tidak menyimpan hal khusus environment, work item yang mengubah skema tetap butuh salinan sendiri. Kalau tidak, skemanya berubah di bawah work item lain yang masih dites.
  • Kalau biaya setup-nya lebih besar daripada keuntungan mengerjakan paralel, jangan dipakai. Kerjakan satu work item dalam satu waktu saja. Worktree itu jalan pintas: kalau pekerjaan paralel di satu repository jadi hal biasa, jawaban yang lebih baik adalah environment lokal berbasis container untuk tiap branch, atau environment yang otomatis di-deploy untuk tiap Pull Request.

Tentukan nama branch sebelum push pertama

Nama branch kelihatannya gampang diganti belakangan. Kenyataannya tidak, begitu Pull Request-nya sudah terbuka.

Mengganti nama branch yang sudah punya Pull Request terbuka akan menutup Pull Request tersebut. PR-nya tetap menunjuk ke nama lama, yang sudah tidak ada lagi. GitHub bisa memindahkan base branch sebuah PR, tapi tidak pernah head branch-nya. PR yang sudah tertutup tidak bisa dibuka lagi kalau head branch-nya sudah hilang, jadi satu-satunya jalan adalah membuat Pull Request baru, dengan nomor baru dan tanpa satu pun komentar review yang lama.

Konvensi

  • Periksa nama branch terhadap halaman Code Repository sebelum git push yang pertama.
  • Jangan pernah mengganti nama branch yang sudah punya Pull Request terbuka.

Jangan mengubah branch yang sudah di-push

Begitu sebuah branch ada di remote, orang lain dan Pull Request itu sendiri bergantung pada commit-commit-nya tetap di tempatnya. Di sini branch-nya juga hidup melewati beberapa kali kenaikan, jadi bisa ada lebih dari satu Pull Request yang menunjuk ke branch tersebut.

Konvensi

  • Setelah push pertama, jangan pakai git commit --amend, git rebase, atau apa pun yang butuh git push --force.
  • Perbaiki kesalahan dengan commit baru di atasnya.
  • Aturan ini berlaku juga untuk temporary branch, bukan hanya branch permanen.

Pull Request

Pull Request adalah tempat perubahan dijelaskan dan di-review. Work item menyimpan latar belakangnya; Pull Request menyimpan apa yang perlu dilihat langsung oleh reviewer.

Konvensi

  • Judulnya sama dengan commit subject, supaya daftar Pull Request yang terbuka terbaca seperti daftar perubahan.
  • Kalau project-nya memakai branch per environment, awali judulnya dengan nama target branch di dalam tanda kurung siku, karena satu branch yang sama menghasilkan beberapa Pull Request yang nyaris identik:
[staging] fix(order): [PROJ-123] correct the order total when a voucher is removed

Commit subject-nya sendiri tidak memakai awalan ini.

  • Body memuat bagian berikut: Problem, Root cause, Fix, Testing. Tulis masing-masing secukupnya saja.
  • Jangan menambahkan baris atribusi tool, misalnya baris "Generated with".
  • Baca daftar file yang berubah sebelum minta review. Ada file yang tidak kamu sentuh berarti branch-nya dibuat dari branch yang salah, dan branch itu harus diulang.
  • Hapus branch-nya hanya setelah sampai di target terakhir. Kalau dihapus setelah merge pertama, tidak ada lagi yang bisa dinaikkan.

Repository dengan branch per environment

Di sini tiap branch permanen di-deploy ke environment-nya sendiri. Sebuah work item disetujui untuk satu environment dulu sebelum lanjut ke berikutnya, jadi isi tiap branch berbeda banyaknya: branch kerja paling banyak, production paling sedikit.

Yang membuat ini tetap rapi adalah sifat bersarang-nya. Semua yang ada di production juga ada di testing, dan semua yang ada di testing juga ada di branch kerja. Isinya tidak pernah sama persis, karena branch kerja selalu memuat pekerjaan yang belum disetujui, tapi tidak ada satu pun yang ada di branch lebih awal tapi hilang di branch berikutnya.

Konvensi

  • Jangan pernah commit di branch permanen.
  • Jangan pernah me-merge satu branch permanen ke branch permanen lain. Itulah yang merusak sifat bersarang tadi dan menyeret pekerjaan yang belum disetujui ikut naik.
  • Buat branch-nya dari production, lalu merge branch yang sama itu ke tiap target seiring status work item-nya berubah. Jangan menyalin commit-nya dengan git cherry-pick — salinan punya commit ID yang berbeda, dan setelah itu tidak ada perintah yang bisa memberitahu perubahan itu sebenarnya ada di mana saja.
  • Buka Pull Request untuk semua target sejak awal, dan hanya yang ke production yang dibuat draft. Pull Request ke branch kerja dan branch testing dibuka siap di-review, apa pun status work item-nya — itu alur sehari-hari, dan QA tidak bisa memindahkan status sebelum perubahannya ada di shared development environment.
  • Hanya Pull Request ke production yang menunggu sebagai draft, karena itulah yang tidak boleh ter-merge tidak sengaja sebelum klien menyetujui. Draft tidak bisa di-merge, jadi gerbangnya terjaga dengan sendirinya.
  • Tandai Pull Request ke production siap di-review saat work item-nya sampai di status untuk itu. Persetujuan untuk testing bukan persetujuan untuk production.
  • Membuka semuanya sejak awal juga membuat GitHub menampilkan konflik begitu muncul, bukan baru di hari rilis.
  • Branch yang belum di-merge ke production adalah daftar pekerjaan yang sedang berjalan. Kalau diurutkan berdasarkan tanggal, daftar itu sekaligus jadi laporan branch yang mangkrak:
git fetch origin --prune
git for-each-ref --no-merged=origin/main --sort=committerdate --format='%(committerdate:short)  %(refname:short)' refs/remotes/origin

Pakai untuk mencari pekerjaan yang terlepas dari tracker work item, dan untuk melihat branch yang sudah ditinggalkan dan sebaiknya dihapus.

Hotfix

Hotfix memperbaiki sesuatu yang sudah rusak di production. Hotfix melompati urutan biasa dan masuk ke production lebih dulu, dan hanya itu yang membuatnya berbeda.

Konvensi

  • Buat dari branch production, sama seperti branch lainnya.
  • Merge ke production dulu, lalu merge juga ke branch testing dan branch kerja. Hotfix yang hanya ada di production merusak sifat bersarang tadi, dan bug-nya akan muncul lagi begitu branch yang lebih lama dinaikkan.
  • Buat sekecil mungkin. Hotfix melewatkan pengujian yang seharusnya didapat dari branch-branch sebelumnya.

Repository dengan satu environment

Tool internal, shared library, atau situs dokumentasi di-deploy ke satu tempat saja, dan tidak ada yang menyetujui rilisnya tahap demi tahap. Tidak ada yang perlu dinaikkan, jadi cukup satu branch permanen dan itulah satu-satunya target.

Konvensi

  • Pakai temporary branch dan Pull Request kalau perubahannya besar, menyentuh kode yang sedang dikerjakan orang lain, atau perlu di-review dulu sebelum masuk. Kalau ragu, pakai Pull Request.
  • Perubahan kecil dengan risiko rendah boleh langsung di-commit di branch permanen tersebut.
  • Hapus branch-nya setelah di-merge. Target-nya cuma satu, jadi tidak ada lagi yang perlu dinaikkan.
  • Semua aturan lain di halaman ini tetap berlaku: satu work item, satu branch, satu commit, ID di nama branch, dan nama branch sudah final sebelum push pertama.