Di Halaman Ini

git commit

Ringkasnya: git commit mengambil snapshot dari Staging Area (index) Anda dan menuliskannya secara permanen ke database objek Git. Di balik layar, Git mengemas struktur direktori Anda ke dalam objek tree, menulis objek commit yang mencantumkan metadata (author, committer, hash commit parent, dan pesan), lalu memperbarui ref branch aktif agar menunjuk ke hash commit baru.


Apa Sebenarnya yang Dilakukan git commit?

Untuk memahami git commit, Anda perlu meninggalkan anggapan umum bahwa Git melacak perubahan sebagai “diff” atau “delta”. Di Git, setiap commit adalah snapshot lengkap dari seluruh proyek.

Saat melakukan commit, Anda tidak menyimpan daftar perubahan baris. Sebaliknya, Anda mengambil foto staging area dan memberinya identifier unik yang permanen. Jika sebuah file tidak berubah dalam suatu commit, Git tidak menggandakannya; Git cukup menunjuk ke objek blob yang sudah ada dari commit sebelumnya. Ini disebut berbagi struktur.

graph TD
    subgraph "A Git Commit Object"
        C[Commit Object<br>Hash: 8a4c10...] -->|Points to| T[Root Tree Object<br>Hash: 4a2b99...]
        C -->|Points to| P[Parent Commit Hash<br>Hash: 55a420...]
        C -.->|Metadata| M[Author, Committer, Timestamp, Message]
    end

Struktur Objek Commit

Secara internal, commit direpresentasikan sebagai file plaintext sederhana yang berisi metadata terstruktur. Saat Git melakukan hashing terhadap plaintext ini menggunakan SHA-1, Git menghasilkan identifier heksadesimal sepanjang 40 karakter.

Objek commit mentah berisi bidang berikut:

  1. tree: Pointer (hash) ke objek tree tingkat teratas (root) yang merepresentasikan direktori root repository.
  2. parent: Hash commit sebelumnya (atau beberapa commit).
    • Commit awal tidak memiliki parent.
    • Commit biasa memiliki satu parent.
    • Merge commit memiliki dua parent atau lebih.
  3. author: Nama, email, dan timestamp Unix orang yang menulis kode.
  4. committer: Nama, email, dan timestamp Unix orang yang melakukan commit (misalnya, saat patch diterapkan oleh maintainer).
  5. gpgsig: Tanda tangan kriptografis (opsional) jika commit ditandatangani.
  6. message: Deskripsi tekstual yang menjelaskan alasan perubahan dibuat.

Apa yang Terjadi di Dalam .git/ (Eksplorasi langsung)

Mari melihat bagian dalam repository untuk menelusuri cara Git membangun objek tree dan commit langkah demi langkah.

Langkah 1: Lakukan Stage pada File dan Periksa Index

Pertama, pastikan kita memiliki repository yang sudah diinisialisasi dan sebuah file yang sudah di-stage menggunakan git add.

$ mkdir git-commit-demo && cd git-commit-demo
$ git init
Initialized empty Git repository in /git-commit-demo/.git/

$ echo "console.log('hello world');" > app.js
$ git add app.js

Pada tahap ini, file dikompresi menjadi objek blob dan dicatat di file .git/index. Mari kita verifikasi:

$ git ls-files --stage
100644 6be02374db118b9fb99cd98c6b403e5a558d0d57 0	app.js

Hash 40 karakter 6be02374db118b9fb99cd98c6b403e5a558d0d57 adalah ID SHA-1 Git untuk blob yang berisi console.log('hello world'); (27 byte ditambah newline yang ditulis oleh echo, jadi totalnya 28 byte). Jika editor atau shell Anda menulis baris tersebut dengan cara berbeda, hash blob Anda akan berbeda — pada content addressing, hash dihitung dari byte file yang persis.

Catatan tentang hash dalam pelajaran ini: hash blob app.js di atas (6be02374…) bersifat tepat dan dapat direproduksi karena blob hanya bergantung pada isi file. Hash commit dan tree memuat timestamp serta zona waktu author/committer, sehingga hash commit yang disingkat dalam output di bawah (misalnya d4a123f) hanya representatif. Menjalankan perintah yang sama persis di repository baru akan menghasilkan struktur yang sama, tetapi ID commit dan tree yang berbeda.

Langkah 2: Buat Commit

Sekarang, mari tulis commit pertama kita.

$ git commit -m "feat: introduce logging script"
[main (root-commit) d4a123f] feat: introduce logging script
 1 file changed, 1 insertion(+)
 create mode 100644 app.js

Mari periksa referensi branch di dalam .git/refs/heads/. File branch aktif main seharusnya kini berisi hash lengkap commit sepanjang 40 karakter:

$ cat .git/refs/heads/main
d4a123f4c7b8d80c0ef14815a5bb1d6a362bf2c9

Dan .git/HEAD memberi tahu Git branch mana yang aktif:

$ cat .git/HEAD
ref: refs/heads/main

Langkah 3: Uraikan Objek Commit

Mari periksa objek commit yang dibuat menggunakan perintah plumbing git cat-file:

# Print type of the object
$ git cat-file -t d4a123f4c7b8d80c0ef14815a5bb1d6a362bf2c9
commit

# Print raw content of the commit object
$ git cat-file -p d4a123f4c7b8d80c0ef14815a5bb1d6a362bf2c9
tree b8a27d0ef093ab7e20cf7b68a417534431e21b7b
author Purna Pattela <purna@example.com> 1772960000 +0000
committer Purna Pattela <purna@example.com> 1772960000 +0000

feat: introduce logging script

Perhatikan bahwa objek commit tidak memuat isi file atau diff. Objek ini menunjuk ke objek tree dengan hash b8a27d0.... Mari periksa tree tersebut:

$ git cat-file -p b8a27d0ef093ab7e20cf7b68a417534431e21b7b
100644 blob 6be02374db118b9fb99cd98c6b403e5a558d0d57	app.js

Objek tree berfungsi seperti daftar isi direktori. Objek ini memetakan nama file app.js ke permission file (100644) dan blob isi yang dikompresi dengan zlib (6be0237...).

Langkah 4: Tambahkan Subdirektori dan Verifikasi Parent

Mari tambahkan subdirektori untuk melihat cara Git menangani folder bertingkat.

$ mkdir src
$ echo "const port = 3000;" > src/config.js
$ git add src/config.js
$ git commit -m "chore: add source config"
[main 7f2b58c] chore: add source config
 1 file changed, 1 insertion(+)
 create mode 100644 src/config.js

Mari baca commit kedua ini:

$ git cat-file -p 7f2b58c
tree a832dbf521b4a56c071d2b512c98a3e74211a512
parent d4a123f4c7b8d80c0ef14815a5bb1d6a362bf2c9
author Purna Pattela <purna@example.com> 1772960100 +0000
committer Purna Pattela <purna@example.com> 1772960100 +0000

chore: add source config

Perhatikan baris baru: parent d4a123f.... Baris ini menunjuk kembali ke commit pertama dan menghubungkan keduanya dalam rantai riwayat.

Mari lihat tree dari commit baru ini:

$ git cat-file -p a832dbf521b4a56c071d2b512c98a3e74211a512
100644 blob 6be02374db118b9fb99cd98c6b403e5a558d0d57	app.js
040000 tree f3b3a3c9e6db5832a875a6c11d2b270a2936274b	src

Alih-alih mencantumkan daftar file datar, objek tree root menunjuk ke objek tree lain (yang merepresentasikan direktori src/, ditandai dengan mode 040000). Jika kita melihat isi tree src yang bertingkat:

$ git cat-file -p f3b3a3c9e6db5832a875a6c11d2b270a2936274b
100644 blob c8384df24a5611dfd9a1db4b86270a1a8a25c156	config.js

Arsitektur tree di dalam tree ini mencerminkan filesystem Anda dengan sempurna.


Opsi Perintah secara Mendetail dan Penggunaan Lanjutan

1. Amend Commit Terakhir (git commit --amend)

Jika Anda salah ketik dalam pesan commit atau lupa melakukan staging terhadap perubahan sebelum commit, Anda dapat menjalankan amend pada commit terakhir:

$ git add forgotten_file.txt
$ git commit --amend -m "chore: add source config and settings"

Di balik layar: Karena commit di Git bersifat tidak dapat diubah (hash SHA-1-nya dihitung dari isinya), Git tidak dapat mengedit commit yang sudah ada. Sebaliknya, --amend membuat objek commit baru yang menunjuk ke tree baru dan pesan yang diubah, dengan parent berupa parent dari commit lama. Git kemudian memperbarui pointer branch ke commit baru dan membiarkan commit lama menjadi yatim.

graph TD
    subgraph "How Amend Works"
        C1[Commit 1] --> C2[Commit 2: Original]
        C1 --> C3[Commit 3: Amended]
        Branch[Branch Ref: main] -->|Moved from C2 to C3| C3
    end
    style C2 fill:#faa,stroke:#333
    style C3 fill:#afa,stroke:#333

2. Lewati Staging Area (git commit -a)

Anda dapat melewati staging dengan menggunakan flag -a (atau --all). Flag ini memberi tahu Git untuk otomatis melakukan staging pada semua file yang dimodifikasi dan dihapus, lalu langsung menulis commit:

$ git commit -am "refactor: simplify logger interface"

[!WARNING] Perintah ini tidak akan melakukan staging pada file baru yang belum dilacak. Jika Anda membuat file yang benar-benar baru, jalankan git add sebelum menjalankan git commit -a.

3. Menandatangani Commit dengan GPG atau SSH (git commit -S)

Dalam lingkungan produksi, sangat penting untuk memverifikasi bahwa commit benar-benar berasal dari author yang tercantum. Anda dapat menandatangani commit secara kriptografis:

$ git commit -S -m "feat: release critical payment gateway integration"

Perintah ini menandatangani commit menggunakan kunci privat lokal. GitHub atau GitLab kemudian dapat menampilkan badge “Verified” di samping commit dengan mencocokkan tanda tangan tersebut dengan kunci publik Anda.


Skenario Dunia Nyata: Menulis Commit Atomik

Basis kode yang sehat bergantung pada commit atomik. Commit atomik adalah commit yang mengerjakan satu hal logis saja. Commit tersebut harus memuat semua perubahan yang diperlukan untuk menerapkan satu fitur atau memperbaiki satu bug, dan tidak lebih.

Misalnya, jika Anda sedang membangun sistem autentikasi, jangan menulis pesan commit seperti implemented login and fixed layout issues on homepage. Jika perbaikan tata letak homepage menimbulkan masalah lain, melakukan revert terhadap commit itu juga akan menghapus sistem login!

Sebaliknya, pecah pekerjaan menggunakan git add dan commit terpisah:

# First, stage only the layout changes
$ git add src/styles.css
$ git commit -m "fix(styles): repair home page navigation alignment"

# Next, stage the login files
$ git add src/auth/
$ git commit -m "feat(auth): implement user authentication mechanism"

Struktur yang rapi ini membuat audit riwayat menggunakan git log menjadi mudah dan memungkinkan developer mengisolasi masalah dengan aman.


Jebakan dan Kesalahan Umum

1. Amend Commit yang Sudah Di-push

Jangan pernah menjalankan git commit --amend pada commit yang sudah di-push ke remote (seperti GitHub) yang digunakan bersama developer lain.

  • Mengapa: Amend mengubah hash commit. Jika Anda melakukan force-push terhadap commit hasil amend, tindakan itu akan menimpa riwayat untuk semua orang dan menimbulkan konflik merge yang merepotkan saat mereka menjalankan pull.
  • Aturan praktis: Hanya lakukan amend pada commit yang hanya ada di komputer lokal Anda.

2. Kesalahan Commit Kosong

Jika Anda mencoba menjalankan git commit saat tidak ada perubahan yang di-stage, Git akan menolak perintah tersebut:

$ git commit -m "nothing changes"
On branch main
nothing to commit, working tree clean
  • Perbaikan: Jika Anda memang perlu membuat commit tanpa modifikasi file (misalnya untuk memicu runner build CI/CD), gunakan flag override:
$ git commit --allow-empty -m "trigger: run test suite in pipeline"

3. Kebingungan Author dan Committer

Terkadang, dalam riwayat proyek, Anda akan melihat sebuah commit mencantumkan satu orang sebagai Author dan orang lain sebagai Committer.

  • Author: Orang yang menulis perubahan kode sebenarnya.
  • Committer: Orang yang menerapkan commit (misalnya menggunakan git rebase atau menerapkan patch).
  • Biasanya, keduanya adalah orang yang sama. Namun, jika Anda menjalankan rebase atau squash pull request milik orang lain di GitHub, Anda menjadi Committer, sementara mereka tetap menjadi Author.

Referensi Cepat Perintah

PerintahTindakan
git commitMembuka editor terminal untuk menulis pesan commit multibaris.
git commit -m "msg"Melakukan commit terhadap perubahan yang di-stage dengan pesan singkat inline.
git commit -a -m "msg"Melakukan stage pada file yang dimodifikasi/dihapus dan melakukan commit dalam satu langkah.
git commit --amendMelakukan amend pada commit terakhir (menambahkan file yang baru di-stage dan/atau memperbarui pesan).
git commit --amend --no-editMelakukan amend pada commit terakhir dengan file baru, tetapi mempertahankan pesan yang sama persis.
git commit --allow-empty -m "msg"Memaksa commit meskipun tidak ada perubahan yang di-stage atau dimodifikasi.
git commit -S -m "msg"Menandatangani commit secara kriptografis.

FAQ (Pertanyaan yang Sering Diajukan)

Apa perbedaan antara git commit dan git push?

git commit adalah perintah lokal. Perintah ini mencatat snapshot di database direktori lokal Anda (.git/objects/). Perintah ini tidak menghubungi server eksternal mana pun. git push adalah perintah jaringan yang mengunggah commit, tree, dan blob lokal ke repository remote (seperti GitHub, GitLab, atau server yang di-host sendiri) agar dapat dibagikan dengan orang lain.

Bagaimana Git menghitung hash commit 40 karakter?

Git melakukan hashing terhadap header dan isi objek commit menggunakan SHA-1. Isinya mencakup hash tree, hash parent, info author, info committer, dan pesan commit. Karena perhitungan hash mencakup timestamp saat ini, dua commit yang dibuat dengan file dan pesan yang persis sama tetap akan memiliki hash yang berbeda.

Bisakah saya mengembalikan atau menghapus commit terakhir?

Bisa. Jika Anda sudah melakukan commit terhadap perubahan tetapi ingin membatalkan commit itu sambil mempertahankan perubahan di working directory (dan mengeluarkannya dari staging), jalankan:

git reset --soft HEAD~1

Jika Anda ingin menghapus commit terakhir sepenuhnya dan membuang semua modifikasi, jalankan:

git reset --hard HEAD~1

(Peringatan: git reset --hard tidak mudah dibatalkan; pastikan pekerjaan Anda sebelum menjalankannya!)

Apa itu state detached HEAD?

Jika Anda menjalankan checkout pada hash commit tertentu (misalnya, git checkout a1b2c3d - tautan git-checkout), bukan pada branch, pointer HEAD Anda menunjuk langsung ke objek commit, bukan ke ref branch. Jika Anda melakukan commit dalam state ini, tidak ada branch yang menunjuk ke commit tersebut. Jika Anda berpindah branch, commit baru Anda akan menjadi yatim dan akhirnya dihapus oleh garbage collection Git. Selalu pastikan Anda berada di sebuah branch sebelum melakukan commit (tautan git-branch).


Uji Pengetahuan Anda

Memuat kuis…