Program
"Commit lebih awal, commit sesering mungkin" adalah mantra populer dalam pengembangan perangkat lunak saat menggunakan Git. Dengan melakukannya, setiap perubahan terdokumentasi dengan baik, kolaborasi meningkat, dan pelacakan evolusi proyek menjadi lebih mudah. Namun, ini juga dapat menyebabkan terlalu banyak commit.
Di sinilah pentingnya melakukan squash commit. Squash commit adalah proses menggabungkan beberapa entri commit menjadi satu commit yang utuh.
Sebagai contoh, misalkan kita mengerjakan sebuah fitur untuk mengimplementasikan formulir login, dan kita membuat empat commit berikut:

Setelah fitur selesai, untuk keseluruhan proyek, commit-commit ini terlalu rinci. Kita tidak perlu tahu di masa mendatang bahwa kita menemui bug yang diperbaiki selama pengembangan. Untuk memastikan riwayat yang bersih di branch utama, kita melakukan squash terhadap commit-commit ini menjadi satu commit:

Cara Melakukan Squash Commit di Git: Interactive Rebase
Metode paling umum untuk melakukan squash commit adalah menggunakan interactive rebase. Kita memulainya dengan perintah:
git rebase -i HEAD~<number_of_commits>
Ganti <number_of_commits> dengan jumlah commit yang ingin kita squash.
Dalam kasus kita, ada empat commit, jadi perintahnya adalah:
git rebase -i HEAD~4
Menjalankan perintah ini akan membuka editor baris perintah interaktif:

Bagian atas menampilkan commit, sementara bagian bawah berisi komentar tentang cara melakukan squash commit.
Kita melihat ada empat commit. Untuk setiap commit, kita harus memutuskan perintah mana yang akan dijalankan. Kita memperhatikan perintah pick (p) dan squash (s). Untuk melakukan squash keempat commit ini menjadi satu commit, kita bisa pick commit pertama dan squash tiga sisanya.
Kita menerapkan perintah dengan mengubah teks sebelum setiap commit, khususnya mengganti pick menjadi s atau squash untuk commit kedua, ketiga, dan keempat. Untuk melakukan edit ini, kita perlu masuk ke mode “INSERT” di editor teks baris perintah dengan menekan tombol i di keyboard:

Setelah menekan i, teks -- INSERT -- akan muncul di bagian bawah, menandakan bahwa kita telah masuk ke mode insert. Sekarang, kita dapat menggerakkan kursor dengan tombol panah, menghapus karakter, dan mengetik seperti di editor teks standar:

Setelah kita puas dengan perubahan, kita perlu keluar dari mode insert dengan menekan tombol Esc di keyboard. Langkah berikutnya adalah menyimpan perubahan dan keluar dari editor. Untuk melakukannya, pertama tekan tombol : untuk memberi tahu editor bahwa kita akan menjalankan perintah:

Di bagian bawah editor, sekarang kita melihat titik dua : yang meminta kita memasukkan perintah. Untuk menyimpan perubahan, gunakan perintah w yang berarti "write". Untuk menutup editor, gunakan q yang berarti "quit". Kedua perintah ini dapat digabung dan diketik bersama wq:

Untuk menjalankan perintah, tekan tombol Enter. Tindakan ini akan menutup editor saat ini dan membuka editor baru, memungkinkan kita memasukkan pesan commit untuk commit hasil squash. Editor akan menampilkan pesan bawaan yang terdiri dari pesan dari keempat commit yang kita squash:

Saya menyarankan untuk memodifikasi pesan agar secara akurat mencerminkan perubahan yang diterapkan oleh commit gabungan ini—bagaimanapun, tujuan dari squash adalah menjaga riwayat tetap bersih dan mudah dibaca.
Untuk berinteraksi dengan editor dan mengedit pesan, tekan i lagi untuk masuk ke mode edit dan sunting pesan sesuai keinginan.

Dalam kasus ini, kita mengganti pesan commit menjadi "Implement login form." Untuk keluar dari mode edit, tekan Esc. Lalu simpan perubahan dengan menekan :, memasukkan perintah wq, dan menekan Enter.
Cara Melihat Riwayat Commit
Secara umum, mengingat seluruh riwayat commit bisa jadi menantang. Untuk melihat riwayat commit, kita dapat menggunakan perintah git log. Pada contoh yang disebutkan, sebelum melakukan squash, menjalankan perintah git log akan menampilkan:

Untuk menavigasi daftar commit, gunakan tombol panah atas dan bawah. Untuk keluar, tekan q.
Kita dapat menggunakan git log untuk memastikan squash berhasil. Menjalankannya setelah squash akan menampilkan satu commit dengan pesan baru:

Mendorong commit yang sudah di-squash
Perintah di atas akan berlaku pada repositori lokal. Untuk memperbarui repositori remote, kita perlu push perubahan. Namun, karena kita mengubah riwayat commit, kita perlu melakukan force push menggunakan opsi --force:
git push --force origin feature/login-form
Force push akan menimpa riwayat commit pada branch remote dan berpotensi mengganggu orang lain yang bekerja pada branch tersebut. Sebaiknya berkomunikasi dengan tim sebelum melakukan ini
Cara yang lebih aman untuk force push, yang mengurangi risiko mengganggu kolaborator, adalah menggunakan opsi --force-with-lease:
git push --force-with-lease origin feature/login-form
Opsi ini memastikan kita hanya melakukan force push jika branch remote belum diperbarui sejak fetch atau pull terakhir kita.
Melakukan squash pada commit tertentu
Bayangkan kita memiliki lima commit:

Misalkan kita ingin mempertahankan commit 1, 2, dan 5 serta melakukan squash pada commit 3 dan 4.

Saat menggunakan interactive rebase, commit yang ditandai untuk squash akan digabungkan dengan commit yang tepat berada sebelumnya. Dalam kasus ini, artinya kita ingin melakukan squash Commit4 agar digabung ke Commit3.
Untuk melakukannya, kita harus memulai interactive rebase yang mencakup kedua commit ini. Dalam kasus ini, tiga commit sudah cukup, jadi kita gunakan perintah:
git rebase -i HEAD~3
Lalu, kita setel Commit4 ke s agar di-squash dengan Commit3:

Setelah menjalankan perintah ini dan menampilkan daftar commit, kita melihat bahwa commit 3 dan 4 telah di-squash menjadi satu sementara sisanya tetap tidak berubah.

Melakukan squash mulai dari commit tertentu
Dalam perintah git rebase -i HEAD~3, bagian HEAD adalah singkatan untuk commit terbaru. Sintaks ~3 digunakan untuk menentukan leluhur dari sebuah commit. Misalnya, HEAD~1 merujuk ke induk dari commit HEAD.

Dalam interactive rebase, commit yang dipertimbangkan mencakup semua commit leluhur hingga commit yang ditentukan dalam perintah. Perhatikan bahwa commit yang ditentukan tidak termasuk:

Alih-alih menggunakan HEAD, kita dapat menentukan hash commit secara langsung. Misalnya, Commit2 memiliki hash dbf3cc118d6d7c08ef9c4a326b26dbb1e3fe9ddf, sehingga perintah:
git rebase -i dbf3cc118d6d7c08ef9c4a326b26dbb1e3fe9ddf
akan memulai rebase dengan mempertimbangkan semua commit yang dibuat setelah Commit2. Oleh karena itu, jika kita ingin memulai rebase pada commit tertentu dan menyertakan commit tersebut, kita dapat menggunakan perintah:
git rebase -i <commit-hash>~1
Menyelesaikan Konflik Saat Melakukan Squash Commit
Saat kita melakukan squash commit, kita menggabungkan banyak perubahan commit menjadi satu commit, yang dapat menimbulkan konflik jika perubahan saling tumpang tindih atau sangat berbeda. Berikut beberapa skenario umum di mana konflik dapat muncul:
- Perubahan yang tumpang tindih: Jika dua atau lebih commit yang di-squash memodifikasi baris yang sama pada sebuah file atau baris yang saling berkaitan, Git mungkin tidak dapat merekonsiliasi perubahan tersebut secara otomatis.
- Keadaan perubahan yang berbeda: Jika satu commit menambahkan potongan kode tertentu dan commit lain memodifikasi atau menghapus potongan kode yang sama, melakukan squash pada commit-commit tersebut dapat menimbulkan konflik yang perlu diselesaikan.
- Mengganti nama dan memodifikasi: Jika sebuah commit mengganti nama file dan commit berikutnya membuat perubahan pada nama lama, melakukan squash pada commit-commit ini dapat membingungkan Git dan menyebabkan konflik.
- Perubahan pada file biner: File biner tidak bisa digabung dengan baik menggunakan alat diff berbasis teks. Jika beberapa commit mengubah file biner yang sama dan kita mencoba melakukan squash, konflik dapat terjadi karena Git tidak dapat merekonsiliasi perubahan tersebut secara otomatis.
- Riwayat yang kompleks: Jika commit memiliki riwayat yang kompleks dengan banyak merge, branching, atau rebase di antaranya, melakukan squash dapat mengakibatkan konflik karena sifat perubahan yang non-linear.
Saat melakukan squash, Git akan mencoba menerapkan setiap perubahan satu per satu. Jika menemukan konflik selama proses, Git akan berhenti dan memungkinkan kita untuk menyelesaikannya.
Konflik akan ditandai dengan penanda konflik <<<<<< dan >>>>>>. Untuk menangani konflik, kita perlu membuka file-file tersebut dan menyelesaikannya secara manual dengan memilih bagian kode mana yang ingin kita pertahankan.
Setelah menyelesaikan konflik, kita perlu men-stage file yang sudah diselesaikan menggunakan perintah git add. Lalu kita dapat melanjutkan rebase menggunakan perintah berikut:
git rebase --continue
Untuk mempelajari lebih lanjut tentang konflik Git, lihat tutorial ini tentang cara menyelesaikan merge conflict di Git.
Alternatif Squash dengan Rebase
Perintah git merge --squash adalah metode alternatif untuk git rebase -i dalam menggabungkan beberapa commit menjadi satu commit. Perintah ini sangat berguna ketika kita ingin menggabungkan perubahan dari sebuah branch ke branch utama sambil melakukan squash semua commit individual menjadi satu. Berikut gambaran cara melakukan squash menggunakan git merge:
- Kita berpindah ke branch target tempat kita ingin memasukkan perubahan.
- Kita menjalankan perintah
git merge --squash <branch-name>mengganti<branch-namedengan nama branch. - Kita melakukan commit perubahan dengan
git commituntuk membuat satu commit yang merepresentasikan semua perubahan dari feature branch.
Sebagai contoh, katakan kita ingin memasukkan perubahan dari branch feature/login-form ke main sebagai satu commit:
git checkout main
git merge --squash feature-branch
git commit -m "Implement login form"
Berikut keterbatasan pendekatan ini dibandingkan git rebase -i:
- Kedalaman kontrol: Kontrol atas commit individual lebih sedikit. Dengan rebase kita dapat memilih commit mana yang akan digabung, sedangkan merge memaksa menggabungkan semua perubahan menjadi satu commit.
- Riwayat perantara: Saat menggunakan merge, riwayat commit individual dari feature branch hilang di branch utama. Ini bisa menyulitkan pelacakan perubahan bertahap yang dibuat selama pengembangan fitur.
- Tinjauan pra-commit: Karena semua perubahan di-stage sebagai satu set perubahan, kita tidak dapat meninjau atau menguji setiap commit secara individual sebelum squash, tidak seperti saat interactive rebase di mana setiap commit dapat ditinjau dan diuji berurutan.
Kesimpulan
Menggabungkan commit yang sering dan kecil ke dalam alur kerja pengembangan mendorong kolaborasi dan dokumentasi yang jelas, tetapi juga dapat membuat riwayat proyek menjadi berantakan. Squash commit memberikan keseimbangan, mempertahankan tonggak penting sekaligus menghilangkan kebisingan dari perubahan iteratif kecil.
Untuk mempelajari lebih lanjut tentang Git, saya merekomendasikan sumber daya berikut:

