Di Halaman Ini
Git Branch: Memahami Sistem Pointer Ringan Git
Ringkasan: Di Git, branch bukan salinan folder atau snapshot berat dari file sumber Anda. Dalam format ref files bawaan Git, branch hanyalah referensi ringan yang dapat berubah—file teks 41 byte berisi hash SHA-1 commit sepanjang 40 karakter dan satu karakter newline—yang disimpan di dalam direktori .git/refs/heads/. Membuat, mengganti nama, atau menghapus branch di Git praktis berlangsung seketika karena operasi itu hanya mengubah file referensi, bukan memodifikasi atau menyalin file di working directory.
Catatan cakupan: Deskripsi “file 41 byte” di halaman ini tepat untuk backend ref
filesbawaan Git ketika sebuah branch unpacked. Referensi juga dapat dikemas ke dalam.git/packed-refsolehgit gc, dan Git mendukung backend reftable alternatif yang sama sekali tidak menyimpan branch sebagai file individual. Perintah dan perilakunya identik dalam semua kasus—yang berbeda hanya representasi di disk. Lihat Git Refs untuk detailnya.
Branch adalah ref, bukan salinan file Anda
Untuk memahami mengapa model branching Git begitu revolusioner, kita perlu membandingkannya dengan Version Control System (VCS) lama seperti Subversion (SVN) atau Perforce. Dalam sistem lama tersebut, membuat branch berarti membuat salinan fisik seluruh pohon direktori proyek. Jika codebase Anda berukuran 5 GB, membuat branch berarti menyalin 5 GB file di server. Operasi ini memerlukan waktu, memboroskan ruang disk, dan membuat developer enggan membuat branch untuk tugas-tugas kecil.
Git tidak menyalin file. Sebaliknya, Git mengatur riwayat proyek sebagai graf berarah tanpa siklus (Directed Acyclic Graph/DAG) yang terdiri dari objek commit. Setiap commit menunjuk ke commit induknya, sehingga membentuk struktur riwayat seperti pohon. Dalam graf ini:
- Commit mewakili snapshot file yang dilacak proyek Anda pada titik waktu tertentu, beserta metadata penulis dan tautan ke commit induk. Lihat /git-commit untuk detail struktur objek commit.
- Branch hanyalah referensi bernama yang menunjuk ke satu commit tertentu dalam graf ini. Branch menjadi titik awal yang digunakan Git untuk menelusuri mundur melalui pointer ke commit induk guna menyusun riwayat branch tersebut.
Bayangkan branch sebagai catatan tempel yang ditempelkan pada node tertentu dalam rangkaian commit. Saat Anda bekerja dan membuat commit baru di branch aktif, Git otomatis memindahkan catatan tempel itu agar menunjuk ke commit terbaru. Karena branch hanyalah referensi (atau “ref”), operasi branching Git hanya perlu menulis atau mengubah string kecil sepanjang 40 karakter.
Untuk melihat lebih jauh sistem referensi umum Git, baca panduan kami tentang /git-refs.
Tiga referensi mudah tertukar: refs/heads/main adalah branch lokal Anda; refs/remotes/origin/main adalah catatan lokal Anda tentang branch remote, yang diperbarui oleh perintah seperti git fetch; dan HEAD menunjukkan branch yang sedang di-checkout, atau commit secara langsung saat detached HEAD. git push yang berhasil juga dapat memperbarui ref remote-tracking yang sesuai.
Mengamati perubahan refs/heads saat membuat branch
Untuk benar-benar memahami mekanisme branch Git, mari kita lakukan penelusuran terminal langkah demi langkah dan amati perubahan direktori .git/ selama operasi branching.
Langkah 1: Menginisialisasi Repository Bersih
Mari buat repository baru, tambahkan commit, lalu lihat struktur direktori .git/.
$ mkdir git-branch-demo
$ cd git-branch-demo
$ git init
Initialized empty Git repository in /users/admin/git-branch-demo/.git/
Pada tahap ini, jika kita mencantumkan isi .git/refs/heads/, direktori tersebut masih sepenuhnya kosong:
$ ls -la .git/refs/heads/
total 0
drwxr-xr-x 2 admin staff 64 Jul 7 10:25 .
drwxr-xr-x 4 admin staff 128 Jul 7 10:25 ..
Belum ada file branch bawaan karena belum ada commit. Mari lihat apa yang ditunjuk oleh .git/HEAD:
$ cat .git/HEAD
ref: refs/heads/main
Meskipun refs/heads/main belum ada di disk, HEAD sudah dikonfigurasi sebelumnya agar menunjuk ke sana. Keadaan ini dikenal sebagai “unborn branch”. Mari buat commit pertama agar branch tersebut muncul.
$ echo "Hello Git Branching!" > README.md
$ git add README.md
$ git commit -m "Initial commit"
[main (root-commit) f24e93e] Initial commit
1 file changed, 1 insertion(+)
create mode 100644 README.md
Sekarang setelah ada commit, mari periksa kembali .git/refs/heads/:
$ ls -la .git/refs/heads/
total 8
drwxr-xr-x 3 admin staff 96 Jul 7 10:27 .
drwxr-xr-x 4 admin staff 128 Jul 7 10:25 ..
-rw-r--r-- 1 admin staff 41 Jul 7 10:27 main
Sebuah file bernama main telah muncul! Mari cetak isi file ini:
$ cat .git/refs/heads/main
f24e93e25b90f46c6a7e0c4a45adbb474f8e6c7c
File tersebut berisi hash commit SHA-1 sepanjang tepat 40 karakter, diikuti karakter newline. Mari verifikasi ke mana hash ini menunjuk menggunakan perintah plumbing git cat-file:
$ git cat-file -t f24e93e25b90f46c6a7e0c4a45adbb474f8e6c7c
commit
Lalu mari cetak isi objek commit untuk melihat bagaimana object itu merepresentasikan snapshot kita:
$ git cat-file -p f24e93e25b90f46c6a7e0c4a45adbb474f8e6c7c
tree 5b38a7c29375ab2b4a53239a584a22c5432a138b
author User <user@example.com> 1783420000 +0000
committer User <user@example.com> 1783420000 +0000
Initial commit
Langkah 2: Membuat Branch Baru
Sekarang, mari buat branch baru bernama feature-login menggunakan perintah git branch:
$ git branch feature-login
Mari periksa isi .git/refs/heads/ untuk melihat apa yang dilakukan Git di balik layar:
$ ls -la .git/refs/heads/
total 16
drwxr-xr-x 4 admin staff 128 Jul 7 10:30 .
drwxr-xr-x 4 admin staff 128 Jul 7 10:25 ..
-rw-r--r-- 1 admin staff 41 Jul 7 10:30 feature-login
-rw-r--r-- 1 admin staff 41 Jul 7 10:27 main
Sebuah file baru bernama feature-login telah dibuat. Mari baca isinya:
$ cat .git/refs/heads/feature-login
f24e93e25b90f46c6a7e0c4a45adbb474f8e6c7c
File itu berisi hash commit yang persis sama dengan main! Git tidak menyalin file sumber apa pun. Git hanya membuat file teks 41 byte yang menunjuk ke commit yang sudah ada (dengan asumsi format ref files bawaan yang belum dikemas). Inilah alasan pembuatan branch berlangsung seketika.
Mari periksa branch aktif dengan membaca .git/HEAD:
$ cat .git/HEAD
ref: refs/heads/main
HEAD masih menunjuk ke main, artinya kita masih berada di branch main. Untuk berpindah branch, kita harus memperbarui referensi HEAD, yang biasanya ditangani oleh perintah seperti git checkout atau git switch. Baca selengkapnya tentang mekanisme ini di /git-checkout.
Langkah 3: Membuat Commit di Branch
Mari pindah ke branch baru dan membuat perubahan.
$ git checkout feature-login
Switched to branch 'feature-login'
Sekarang mari verifikasi .git/HEAD:
$ cat .git/HEAD
ref: refs/heads/feature-login
HEAD telah diperbarui agar menunjuk ke refs/heads/feature-login. Mari buat commit baru:
$ echo "Login Form UI" > login.html
$ git add login.html
$ git commit -m "Add login page"
[feature-login a7c8e9d] Add login page
1 file changed, 1 insertion(+)
create mode 100644 login.html
Mari periksa isi referensi branch sekarang:
$ cat .git/refs/heads/feature-login
a7c8e9d8928424ef245eefb925b42d3851b2c129
$ cat .git/refs/heads/main
f24e93e25b90f46c6a7e0c4a45adbb474f8e6c7c
feature-login telah bergerak maju dan menunjuk ke commit baru a7c8e9d.... Namun, main tetap menunjuk ke f24e93e.... Jika kita memeriksa riwayat menggunakan /git-log:
$ git log --oneline --graph --all
* a7c8e9d (HEAD -> feature-login) Add login page
* f24e93e (main) Initial commit
Graph tersebut menunjukkan bahwa feature-login telah bercabang. Pointer branch main tetap, sedangkan feature-login bergerak bersama HEAD. Jika nanti kita memutuskan untuk menggabungkan branch ini, Git akan membaca pointer tersebut untuk menghitung riwayatnya. Pelajari hal ini di /git-merge.
Membuat, mengganti nama, dan menghapus branch
Perintah git branch bukan hanya untuk membuat referensi; perintah ini juga merupakan alat serbaguna untuk mengelola, menanyakan informasi, dan mengaudit graf branch.
1. Mencantumkan dan Memfilter Branch
Saat mengelola proyek besar, Anda sering menemukan puluhan branch lokal dan remote. Git menyediakan filter agar semuanya tetap teratur.
- Mencantumkan semua branch (lokal dan remote):
Perintah ini menampilkan branch lokal dalam satu warna (misalnya hijau) dan branch pelacak remote (yang disimpan di$ git branch -a.git/refs/remotes/) dalam warna lain (misalnya merah). - Memfilter berdasarkan status merge:
Sebelum membersihkan branch lama, Anda perlu mengetahui branch mana yang sudah berhasil di-merge ke branch aktif saat ini:
Untuk melihat branch yang berisi pekerjaan yang belum di-merge ke branch aktif saat ini:$ git branch --merged
Menjalankan$ git branch --no-mergedgit branch -dpada branch mana pun dalam daftar--no-mergedakan gagal kecuali dipaksa. - Daftar lengkap dengan pelacakan upstream:
Perintah ini menampilkan hash hash commit terbaru, baris subjek commit, dan status pelacakan upstream (misalnya apakah branch lokal Anda lebih maju atau tertinggal dari pasangannya di remote).$ git branch -vv
2. Internal Penghapusan dan Pengumpulan Sampah
Menghapus branch adalah tugas umum, tetapi cara kerjanya bergantung pada flag yang digunakan.
- Hapus Aman (
-datau--delete):
Git akan mencegah Anda menghapus branch jika branch itu berisi commit yang tidak dapat dijangkau dari branch aktif saat ini atau branch upstream. Hal ini mencegah hilangnya pekerjaan secara tidak sengaja.$ git branch -d feature-login - Hapus Paksa (
-Datau-d --force):
Perintah ini memberi tahu Git: “Hapus referensinya, apa pun keadaannya.”$ git branch -D feature-login
Apa yang terjadi pada commit?
Menghapus branch akan menghapus ref-nya; perintah ini tidak langsung menghapus objek commit. Jika tidak ada ref lain yang mencapai commit tersebut, commit itu menjadi tidak terjangkau dan untuk sementara masih bisa dipulihkan melalui reflog. Git pada akhirnya dapat memangkas objek yang tidak terjangkau, dan waktunya bergantung pada konfigurasi serta kondisi repositori. Jika pekerjaan itu penting, buat branch lain sebelum pembersihan; lihat Git objects untuk siklus hidup objek.
3. Melacak Branch Upstream
Saat berkolaborasi, branch lokal Anda melacak branch di server remote (seperti GitHub). Konfigurasi pelacakan ini disimpan di .git/config.
Untuk menetapkan branch upstream bagi branch aktif saat ini:
$ git branch -u origin/feature-login
# Or:
$ git branch --set-upstream-to=origin/feature-login
Perintah ini mengubah file .git/config sehingga berisi metadata pelacakan:
[branch "feature-login"]
remote = origin
merge = refs/heads/feature-login
Konfigurasi inilah yang memungkinkan Anda cukup mengetik git pull atau git push tanpa menentukan remote dan nama branch.
Memulihkan branch yang tidak sengaja Anda hapus
Bayangkan Anda sedang membersihkan ruang kerja. Anda mengira telah menggabungkan branch feature-payment ke main, lalu menjalankan:
$ git branch -D feature-payment
Deleted branch feature-payment (was c3b91a2).
Tiba-tiba Anda menyadari bahwa feature-payment ternyata belum di-merge, dan Anda baru saja menghapus pekerjaan berhari-hari! Karena file-file itu tidak lagi terlihat di editor, situasinya tampak seperti bencana.
Cara Memulihkannya:
Karena branch hanyalah referensi, commit-nya sendiri masih ada di database. Anda hanya perlu menemukan hash commit dan memasang referensi branch baru padanya.
- Cari di Reflog:
Reflog mencatat setiap kali posisi
HEADberubah. Jalankan:
Jika diperhatikan,$ git reflog f24e93e HEAD@{0}: checkout: moving from feature-payment to main c3b91a2 HEAD@{1}: commit: Add Stripe Integration and webhooks f24e93e HEAD@{2}: checkout: moving from main to feature-paymentc3b91a2adalah commit yang kita buat di branchfeature-paymentsebelum berpindah kembali kemain. - Buat Ulang Pointer Branch:
Sekarang, jalankan
git branchdiikuti nama branch baru dan hash yang Anda pulihkan:
Selesai! Git membuat file referensi baru di$ git branch feature-payment c3b91a2.git/refs/heads/feature-paymentyang berisic3b91a2, sehingga pekerjaan Anda langsung pulih.
Kesalahan umum pada perintah branch
1. Mengira git branch Berpindah ke Branch Baru
Menjalankan git branch new-feature hanya membuat pointer. Perintah itu tidak memperbarui HEAD. Jika Anda langsung mulai mengedit file, commit akan masuk ke branch lama (misalnya main). Selalu ingat untuk menjalankan git checkout new-feature (atau gunakan git checkout -b new-feature untuk membuat dan berpindah dalam satu langkah).
2. Benturan Namespace (File vs Direktori)
Karena Git menyimpan ref branch sebagai file di .git/refs/heads/, ref tersebut harus mengikuti aturan path sistem operasi Anda.
- Jika Anda memiliki branch bernama
feature, Git membuat file bernama.git/refs/heads/feature. - Jika kemudian Anda mencoba membuat branch bernama
feature/login, Git harus membuat direktori bernamafeaturedan menempatkan filelogindi dalamnya. - Di sebagian besar sistem, Anda tidak dapat memiliki file dan direktori dengan nama yang sama persis di folder induk yang sama. Hal ini menghasilkan kesalahan berikut:
error: cannot lock ref 'refs/heads/feature/login': 'refs/heads/feature' exists; cannot create 'refs/heads/feature/login' - Perbaikan: Hindari membuat branch generik bernama
featurejika Anda berencana menggunakan namespace bertanda garis miring sepertifeature/logindanfeature/payment.
3. Referensi Lokal Kedaluwarsa ke Branch Remote yang Dihapus
Saat rekan satu tim menghapus branch di server remote, Git lokal Anda masih menyimpannya di .git/refs/remotes/origin/. Hal ini dapat membingungkan.
- Perbaikan: Bersihkan branch pelacak remote yang kedaluwarsa dengan menjalankan:
$ git fetch --prune
Ringkasan perintah branch
| Perintah | Deskripsi | Tindakan internal Git |
|---|---|---|
git branch | Mencantumkan semua branch lokal | Membaca file di dalam .git/refs/heads/ |
git branch <name> | Membuat referensi branch baru | Membuat file 41 byte di .git/refs/heads/<name> (format files default yang belum dikemas) |
git branch -d <name> | Menghapus branch dengan aman jika sudah di-merge | Menghapus file ref; memeriksa keterjangkauan lebih dulu |
git branch -D <name> | Menghapus branch secara paksa | Menghapus file ref tanpa memperhatikan keterjangkauan |
git branch -m <new-name> | Mengganti nama branch aktif saat ini | Mengganti nama file ref di .git/refs/heads/ |
git branch -a | Mencantumkan branch lokal dan remote | Membaca .git/refs/heads/ dan .git/refs/remotes/ |
git branch -vv | Menampilkan status pelacakan dan commit | Menghubungkan file ref lokal dengan pengaturan upstream |
Pertanyaan tentang branch, terjawab
Apa arti “detached HEAD”?
Keadaan “detached HEAD” terjadi ketika HEAD menunjuk langsung ke hash commit tertentu, bukan ke referensi branch bernama.
Misalnya, .git/HEAD dapat berisi ID commit alih-alih ref: refs/heads/main. Commit yang dibuat dalam keadaan ini tidak berada di branch mana pun; setelah berpindah, commit itu bisa menjadi tidak terjangkau dari ref bernama, meskipun reflog dapat membantu memulihkannya. Untuk menyimpan pekerjaan, buat branch saat masih berada di commit tersebut dengan git switch -c rescue-work. Lihat Git refs untuk memahami hubungan HEAD dan ref branch.
Dapatkah dua branch menunjuk ke commit yang sama?
Ya. Beberapa branch dapat menunjuk ke hash commit yang sama persis. Bahkan, saat Anda membuat branch baru dari main, kedua branch menunjuk ke commit yang sama sampai Anda membuat commit baru di salah satunya. Git tidak bermasalah jika beberapa ref berisi string SHA-1 sepanjang 40 karakter yang sama.
Bagaimana cara mendorong branch lokal ke server remote?
Untuk mendorong branch Anda ke repository remote dan menyiapkannya agar melacak remote tersebut, gunakan perintah:
$ git push -u origin <branch-name>
Flag -u (atau --set-upstream) memberi tahu Git untuk membuat hubungan pelacakan, dengan memperbarui file .git/config sehingga push dan pull berikutnya pada branch ini cukup menggunakan git push atau git pull.
Uji pemahaman
Memuat kuis…