Panduan

Git submodule: cara menambah, memperbarui, dan menghapus submodul

Diperbarui: · Skillaria.Top

Git submodule adalah repositori lain yang disisipkan ke dalam proyek Anda dan dikunci pada commit tertentu. Submodul ditambahkan dengan git submodule add <url> <path>, diambil saat kloning dengan git clone --recurse-submodules, diperbarui dengan git submodule update --remote, dan dihapus dengan git submodule deinit lalu git rm.

Git submodule (submodul) adalah repositori Git terpisah yang disisipkan ke dalam folder proyek Anda. Ciri utamanya: repositori induk tidak menyimpan berkas submodul, melainkan referensi ke commit tertentu di dalamnya. Karena itu, siapa pun yang mengkloning proyek akan mendapatkan submodul dalam versi yang sama, sampai Anda sendiri secara eksplisit mengubahnya.

Submodul dipakai ketika Anda ingin menyambungkan pustaka pihak lain tanpa manajer paket, membagi kode bersama di beberapa proyek, atau memisahkan tema tampilan dan firmware ke repositori sendiri dengan riwayatnya.

Cara kerja submodul

Submodul terdiri dari tiga bagian, dan memahami hubungannya menyelesaikan sebagian besar masalah:

  • Berkas .gitmodules di root proyek — di-commit dan mendeskripsikan path mana berasal dari URL mana.
  • Entri gitlink di pohon commit — elemen khusus dengan mode 160000, yang isinya bukan konten melainkan hash commit submodul.
  • Repositori submodul itu sendiri — datanya disimpan di .git/modules/<nama> milik induk, sedangkan di folder submodul ada berkas .git yang menunjuk ke sana.
cat .gitmodules
[submodule "libs/ui-kit"]
	path = libs/ui-kit
	url = https://github.com/example/ui-kit.git

git ls-tree HEAD libs/
160000 commit 8d7c6b5a4f3e2d1c0b9a8f7e6d5c4b3a2f1e0d9c	libs/ui-kit

Perhatikan: induk mengunci commit, bukan branch. Inilah perbedaan mendasar antara submodul Git dan dependensi yang berbunyi «versi terbaru dari main».

Cara menambahkan submodul

git submodule add https://github.com/example/ui-kit.git libs/ui-kit
Cloning into '/home/dev/shop/libs/ui-kit'...
done.

git status
	new file:   .gitmodules
	new file:   libs/ui-kit

git commit -m "Tambahkan ui-kit sebagai submodul"

Perintah ini mengkloning repositori, membuat atau memperbarui .gitmodules, dan menambahkan gitlink ke index. Tinggal commit. Jika path tidak disebutkan, folder akan dinamai sesuai nama repositori.

Jika submodul harus mengikuti branch tertentu saat diperbarui, tentukan sejak awal: git submodule add -b develop <url> <path>. Branch itu akan dicatat di .gitmodules sebagai branch = develop.

URL relatif

Jika submodul berada di server yang sama, Anda bisa memakai path relatif: git submodule add ../ui-kit.git libs/ui-kit. Path ini dihitung relatif terhadap URL remote induk, sehingga bekerja baik melalui SSH maupun HTTPS, tergantung cara Anda mengkloning proyek.

Cara mengkloning proyek yang memiliki submodul

Keluhan paling umum: «sudah saya kloning, tetapi folder submodulnya kosong». Secara default git clone tidak mengunduh submodul. Cara yang benar:

git clone --recurse-submodules https://github.com/example/shop.git

Jika proyek sudah terlanjur dikloning tanpa submodul:

git submodule update --init --recursive

--init mendaftarkan submodul dari .gitmodules ke .git/config lokal, update mengunduhnya dan berpindah ke commit yang dikunci, dan --recursive melakukan hal yang sama untuk submodul di dalam submodul.

Cara memperbarui submodul

Di sini ada dua tugas yang berbeda: «mengambil versi yang sudah di-commit oleh rekan» dan «berpindah ke versi baru pustaka».

Mengambil versi yang dikunci proyek

Setelah git pull di induk, gitlink bisa saja berubah, tetapi berkas submodul tidak ikut diperbarui otomatis. git status akan menampilkan modified: libs/ui-kit (new commits). Sinkronkan dengan:

git pull
git submodule update --init --recursive

Agar tidak perlu melakukannya secara manual, aktifkan otomatisasi: git config submodule.recurse true. Dengan itu, pull, checkout, dan switch akan memperbarui submodul sendiri. Untuk sekali pakai, gunakan git pull --recurse-submodules.

Berpindah ke versi baru pustaka

# Opsi 1: ambil commit terakhir dari branch yang dilacak
git submodule update --remote libs/ui-kit

# Opsi 2: pilih versi secara manual
cd libs/ui-kit
git fetch
git checkout v3.2.0
cd ../..

# Di kedua kasus, kunci versi baru di induk
git add libs/ui-kit
git commit -m "Perbarui ui-kit ke v3.2.0"

--remote mengambil branch dari parameter branch di .gitmodules; jika tidak ada, yang diambil adalah branch yang ditunjuk HEAD remote submodul (biasanya main). Tanpa commit di induk, rekan Anda tidak akan menerima versi baru: pembaruan submodul selalu berupa perubahan gitlink yang harus di-commit.

Untuk melihat apa yang berubah di submodul:

git diff --submodule=log
git config diff.submodule log    # jadikan format ini sebagai default
git submodule status
 8d7c6b5a4f3e2d1c0b9a8f7e6d5c4b3a2f1e0d9c libs/ui-kit (v3.1.0)
+1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b libs/charts (v1.4.0-3-g1a2b3c4)

Arti awalan pada git submodule status: - berarti submodul belum diinisialisasi, + berarti commit saat ini berbeda dari yang dikunci di induk, dan U berarti ada konflik penggabungan.

Cara mengubah isi submodul

Setelah git submodule update, submodul berada dalam keadaan detached HEAD, yaitu pada commit tertentu, bukan pada branch. Jika Anda langsung commit dari kondisi ini, commit mudah hilang saat update berikutnya. Urutan kerja yang benar:

cd libs/ui-kit
git switch main                  # pindah ke branch
# ... perubahan ...
git commit -am "Perbaiki jarak tombol"
git push                         # kirim submodul lebih dulu!
cd ../..
git add libs/ui-kit
git commit -m "ui-kit: perbaiki jarak tombol"
git push

Urutan push sangat penting. Jika induk dikirim lebih dulu, server akan menunjuk ke commit yang tidak bisa diunduh siapa pun selain Anda, dan git submodule update rekan Anda akan gagal dengan error fatal: remote error: upload-pack: not our ref atau did not contain. Untuk melindungi diri, gunakan git push --recurse-submodules=check (menolak push jika submodul belum dikirim) atau =on-demand (mengirim submodul lebih dulu secara otomatis).

Cara menghapus submodul

Dulu penghapusan membutuhkan pengeditan beberapa berkas secara manual. Di versi Git modern, tiga langkah sudah cukup:

git submodule deinit -f libs/ui-kit   # hapus dari .git/config dan kosongkan folder
git rm -f libs/ui-kit                 # hapus gitlink dan entri di .gitmodules
rm -rf .git/modules/libs/ui-kit       # hapus data submodul yang tersimpan
git commit -m "Hapus submodul ui-kit"

Langkah terakhir tidak wajib agar hasilnya benar, tetapi tanpanya saat menambahkan submodul lagi di path yang sama Git bisa mengeluh bahwa folder lokal sudah ada (A git directory for 'libs/ui-kit' is found locally).

Jika URL submodul berubah

Repositori pindah tempat? Perbaiki .gitmodules dan sinkronkan konfigurasi lokal:

git submodule set-url libs/ui-kit https://gitlab.com/example/ui-kit.git
git submodule sync --recursive
git commit -am "Alamat baru ui-kit"

Rekan Anda juga perlu menjalankan git submodule sync setelah pull, karena URL dari .gitmodules hanya disalin ke .git/config saat init atau sync.

Perintah berguna untuk banyak submodul

TugasPerintah
Daftar dan statusgit submodule status --recursive
Menjalankan perintah di setiap submodulgit submodule foreach 'git switch main && git pull'
Mempercepat unduhangit submodule update --init --jobs 4
Unduh tanpa riwayatgit submodule update --init --depth 1
Ringkasan submodul di statusgit config status.submoduleSummary true

Masalah umum dengan submodul

  • Folder kosong setelah kloning — init belum dijalankan. Solusi: git submodule update --init --recursive.
  • «modified: (new commits)» langsung setelah pull — induk menunjuk ke commit lain, tetapi berkasnya masih lama. Solusi: git submodule update.
  • Submodul terlanjur dimundurkan — Anda menjalankan git add . saat submodul masih di commit lama, lalu commit mundurnya versi. Selalu periksa git diff --submodule sebelum commit.
  • Konflik gitlink saat merge — di dua branch submodul diperbarui ke commit yang berbeda. Masuk ke submodul, pilih commit yang benar (sering kali yang lebih baru dan sudah memuat kedua perubahan), lalu git add path dan selesaikan merge.
  • Submodul privat di CI — build tidak bisa mengunduh submodul tanpa akses. Berikan CI kunci atau token untuk repositori submodul; URL relatif mempermudah konfigurasinya.

Submodul dalam tim: kesepakatan

Sebagian besar masalah submodul bukan karena Git, melainkan karena setiap anggota tim bertindak dengan caranya sendiri. Beberapa aturan yang sebaiknya dicatat di README proyek:

  1. Selalu mengkloning dengan --recurse-submodules, dan atur submodule.recurse true pada semua mesin.
  2. Memperbarui submodul dilakukan dalam commit tersendiri dengan pesan yang jelas: versi berapa dan mengapa.
  3. Tidak mengubah kode submodul dari dalam proyek induk tanpa commit tersendiri dan push ke submodul itu sendiri.
  4. Di CI, jalankan eksplisit git submodule update --init --recursive dan pastikan build tidak bergantung pada perubahan lokal.

Untuk memastikan di CI bahwa semua commit submodul yang dikunci benar-benar tersedia, cukup gunakan klon bersih: jika ada yang lupa mengirim submodul, build akan gagal di langkah update, bukan di komputer rekan seminggu kemudian.

git clone --recurse-submodules --jobs 4 "$REPO_URL" build
cd build
git submodule status --recursive

Submodul atau alternatif

Submodul memberikan kontrol versi yang tepat dan riwayat yang terpisah, tetapi menambah langkah manual bagi setiap anggota tim. Jika kodenya berupa pustaka biasa, manajer paket (npm, pip, Composer, modul Go) lebih sederhana. Jika Anda ingin kode pihak lain cukup berada di dalam proyek dan ikut terkloning tanpa perintah tambahan, pertimbangkan git subtree: ia menyalin riwayat ke repositori utama, sehingga rekan tidak perlu tahu apa-apa. Untuk banyak layanan yang saling terkait, tim sering memilih monorepo. Submodul layak dipakai ketika kode yang disisipkan punya siklus hidupnya sendiri, rilisnya sendiri, dan timnya sendiri.

Ringkasan

Git submodule adalah referensi ke commit tertentu di repositori lain. Tambahkan dengan git submodule add, ambil dengan --recurse-submodules atau update --init, perbarui ke versi baru dengan update --remote lalu commit di induk, dan hapus dengan deinit, git rm, serta pembersihan .git/modules. Ingat pula soal detached HEAD di dalam submodul dan urutan push. Alat Git lanjutan dibahas dengan praktik dalam kursus Git.

Pertanyaan umum

Mengapa submodul selalu berada di detached HEAD?

Induk menyimpan hash commit, bukan branch, dan git submodule update memindahkan submodul ke commit itu. Untuk melakukan perubahan, pindah ke branch secara manual, atau gunakan git submodule update --remote --merge.

Bisakah submodul dikunci pada tag?

Tidak langsung, tetapi Anda bisa pindah ke tag di dalam submodul dengan git checkout lalu commit di induk untuk commit hasilnya; di git submodule status, nama tag akan terlihat dalam tanda kurung.

Apakah arsip ZIP dari GitHub menyertakan submodul?

Tidak. Arsip sumber dari GitHub tidak memuat isi submodul, sehingga foldernya kosong. Gunakan git clone --recurse-submodules.

Apa bedanya git submodule dengan git subtree?

Submodul menyimpan referensi ke commit repositori eksternal dan membutuhkan perintah terpisah untuk mengambil kodenya, sedangkan subtree menyalin berkas beserta riwayatnya langsung ke repositori utama.

Bisakah submodul dipindahkan ke folder lain?

Bisa, dengan git mv path-lama path-baru. Git akan memperbarui .gitmodules dan referensi internal, tinggal commit.

Pelajari topik ini lewat video

Topik ini dibahas mendalam dengan praktik di kursus “Git dari Nol hingga Pengembang Percaya Diri”.

Ke kursus