Mengatur repositori Git dengan sub-modul bersarang yang umum

50

Saya penggemar berat sub-modul Git . Saya ingin dapat melacak dependensi bersama dengan versinya, sehingga Anda dapat memutar kembali ke versi sebelumnya dari proyek Anda dan memiliki versi dependensi yang sesuai untuk dibangun dengan aman dan bersih. Selain itu, lebih mudah untuk merilis perpustakaan kami sebagai proyek sumber terbuka karena sejarah untuk perpustakaan terpisah dari aplikasi yang bergantung padanya (dan yang tidak akan bersumber terbuka).

Saya sedang menyiapkan alur kerja untuk beberapa proyek di tempat kerja, dan saya bertanya-tanya bagaimana jadinya jika kita mengambil pendekatan ini sedikit ekstrem daripada memiliki proyek monolitik tunggal. Saya segera menyadari ada potensi cacing dalam benar - benar menggunakan sub-modul.

Misalkan sepasang aplikasi: studiodan player, dan perpustakaan bergantung core, graphdan network, di mana dependensi adalah sebagai berikut:

  • core adalah standalone
  • graphtergantung pada core(sub-modul di ./libs/core)
  • networkdepdends on core(sub-module at ./libs/core)
  • studiotergantung pada graphdan network(sub-modul di ./libs/graphdan ./libs/network)
  • playertergantung pada graphdan network(sub-modul di ./libs/graphdan ./libs/network)

Misalkan kita menggunakan CMake dan masing-masing proyek ini memiliki unit test dan semua pekerjaan. Setiap proyek (termasuk studiodan player) harus dapat dikompilasi mandiri untuk melakukan metrik kode, pengujian unit, dll.

Masalahnya adalah, rekursif git submodule fetch, maka Anda mendapatkan struktur direktori berikut:

studio/
studio/libs/                    (sub-module depth: 1)
studio/libs/graph/
studio/libs/graph/libs/         (sub-module depth: 2)
studio/libs/graph/libs/core/
studio/libs/network/
studio/libs/network/libs/       (sub-module depth: 2)
studio/libs/network/libs/core/

Perhatikan bahwa coredikloning dua kali dalam studioproyek. Selain dari pemborosan ruang disk ini, saya memiliki masalah sistem pembangunan karena saya membangun coredua kali dan saya berpotensi mendapatkan dua versi yang berbeda core.

Pertanyaan

Bagaimana saya mengatur sub-modul sehingga saya mendapatkan dependensi versi dan pembuatan mandiri tanpa mendapatkan banyak salinan sub-modul bersarang yang umum?

Solusi yang mungkin

Jika ketergantungan perpustakaan agak dari saran (yaitu dalam mode "diketahui bekerja dengan versi X" atau "hanya versi X yang didukung secara resmi") dan aplikasi atau perpustakaan yang bergantung pada potensial bertanggung jawab untuk membangun dengan versi apa pun yang mereka sukai, maka Saya bisa membayangkan skenario berikut:

  • Siapkan sistem build untuk graphdan networkberi tahu mereka di mana menemukannya core(mis. Via path compiler include). Tetapkan dua target build, "standalone" dan "dependency", di mana "standalone" didasarkan pada "dependency" dan tambahkan path include untuk menunjuk ke coresub-modul lokal .
  • Memperkenalkan ketergantungan ekstra: studiopada core. Kemudian, studiobuild core, atur path include ke salinan coresub-modulnya sendiri, kemudian build graphdan networkdalam mode "dependensi".

Struktur folder yang dihasilkan terlihat seperti:

studio/
studio/libs/                    (sub-module depth: 1)
studio/libs/core/
studio/libs/graph/
studio/libs/graph/libs/         (empty folder, sub-modules not fetched)
studio/libs/network/
studio/libs/network/libs/       (empty folder, sub-modules not fetched)

Namun, ini memerlukan beberapa keajaiban sistem bangun (saya cukup yakin ini dapat dilakukan dengan CMake) dan sedikit pekerjaan manual pada bagian pembaruan versi (pembaruan graphmungkin juga memerlukan pembaruan coredan networkuntuk mendapatkan versi yang kompatibel coredi semua proyek) .

Ada pemikiran tentang ini?

André Caron
sumber
Perhatikan bahwa masalah ini tidak spesifik untuk cmake: ada untuk sistem build apa pun, termasuk tidak ada sistem! (Yaitu ketika itu dimaksudkan bahwa proyek-super hanya menambahkan sumber perpustakaan; yang termasuk perpustakaan hanya header)
MM

Jawaban:

5

Saya sangat terlambat ke pesta ini, tetapi pertanyaan Anda sepertinya belum memiliki jawaban yang lengkap, dan ini adalah hit yang cukup menonjol dari google.

Saya memiliki masalah yang sama persis dengan C ++ / CMake / Git / Submodules dan saya memiliki masalah yang sama dengan MATLAB / Git / Submodules, yang mendapat beberapa keanehan ekstra karena MATLAB tidak dikompilasi. Saya menemukan video ini baru-baru ini, yang tampaknya mengusulkan "solusi". Saya tidak suka solusinya, karena pada dasarnya itu berarti membuang submodula, tetapi itu menghilangkan masalah. Ini seperti yang direkomendasikan @errordeveloper. Setiap proyek tidak memiliki submodula. Untuk membangun proyek, buat proyek super untuk membangunnya, dan sertakan itu sebagai saudara kandung dari ketergantungannya.

Jadi proyek Anda untuk pengembangan graphmungkin terlihat seperti:

buildgraph/graph
buildgraph/core

dan kemudian proyek Anda untuk studio dapat:

buildstudio/studio
buildstudio/graph
buildstudio/network
buildstudio/core

Super-proyek hanya utama CMakeLists.txtdan banyak submodul. Tetapi tidak ada proyek yang memiliki submodula sendiri.

Satu-satunya biaya yang saya lihat untuk pendekatan ini adalah proliferasi "proyek super" sepele yang hanya didedikasikan untuk membangun proyek nyata Anda. Dan jika seseorang menguasai salah satu proyek Anda, tidak ada cara mudah untuk mengetahui tanpa menemukan proyek super juga, apa dependensinya. Itu mungkin membuatnya duduk sangat jelek di Github, misalnya.

chadsgilbert
sumber
1

Saya kira ketika Anda mengintegrasikan keduanya graphdan networksubmodul ke dalam studio, Anda harus selalu memiliki versi yang sama corepada waktu tertentu dalam sejarah studio. Saya akan simlink studio/libs/coresubmodule ke studio/libs/{graph,network}/libs.

Memperbarui:

Saya membuat beberapa repositori dengan dependensi yang Anda nyatakan:

./core      <--- (v2)
./graph
./graph/libs
./graph/libs/core  <--- (v2)
./graph/.gitmodules
./network
./network/libs
./network/libs/core  <--- (v1)
./network/.gitmodules
./studio
./studio/libs
./studio/libs/graph
./studio/libs/graph/libs
./studio/libs/graph/libs/core <--- (v1)
./studio/libs/graph/.gitmodules
./studio/libs/network
./studio/libs/network/libs
./studio/libs/network/libs/core  <--- (v1)
./studio/libs/network/.gitmodules
./studio/studio
./studio/.gitmodules

v1dan v2dua versi berbeda core. graphmenangani versi 2, sedangkan networkmembutuhkan beberapa pekerjaan dan terjebak pada versi 1. Dalam studio, versi lokal yang disematkan corekedua titik v1untuk memiliki program yang berfungsi. Sekarang, terlepas dari perspektif build, semuanya bekerja dengan baik dengan submodul.

Sekarang saya dapat menghapus direktori berikut:

./studio/libs/network/libs/core

Dan ganti dengan tautan simbolis:

./studio/libs/network/libs/core@ -> ../../graph/libs/core/

Saya melakukan perubahan ini secara lokal dan kehilangan kemampuan untuk memiliki dua versi coredi dalam yang terpisah studio, tetapi saya hanya membangun coresatu kali. Ketika saya siap untuk meningkatkan v2, saya dapat melakukan:

 git submodule update # (--rebase ?)

... di dalam studio / libs / jaringan.

coredump
sumber
Ide tautan simbolis memang terlintas di benak saya, tetapi itu bukan solusi. Jika Anda menautkan dari graph/libs/coreluar, Anda tidak menggunakan submodule. Jika Anda menautkan dari studio/libs/coreke salah satu perpustakaan sub-modul itu sendiri, lalu yang mana yang Anda pilih, graphatau network? Selain itu, apa yang terjadi ketika kedalamannya tiga atau lebih? Akhirnya, bagaimana jika corebisa berbagai revisi. Tidak jelas bahwa Anda ingin menautkan ke salah satu versi coreitu graphdan networkmenggunakan.
André Caron
"Mana yang Anda pilih ?" : coreakan menjadi submodule yang diambil dari coreperpustakaan asli , diperbarui ke versi yang kompatibel untuk keduanya graphdan network(Anda harus memutuskan mana yang baik). Tautan simbolis akan ditambahkan di lokal graphdan networksubmodula (tidak dibuat).
coredump
1
Tautan simbolis yang Anda usulkan untuk ditambahkan graphdan networkakan menunjukkan di luar repositori mereka sendiri (misalnya di tempat lain dalam studioproyek). Bagaimana mereka tahu kapan harus menggunakan sub-modul mereka sendiri versus kapan harus menggunakan tautan simbolik? Mungkin Anda harus menambahkan contoh untuk menunjukkan cara berpikir Anda.
André Caron
0

Saya akan meratakannya untuk memiliki kedalaman sub-modul hanya satu dan memiliki repositori yang akan menampung semua modul sebagai sub-modul dan tidak ada yang lain selain dari README dan skrip build. Akan ada skrip build terpisah untuk setiap paket yang menghubungkan dependensinya. Kalau tidak, Anda dapat memiliki repo terpisah untuk suatu paket.

errordeveloper
sumber
1
Saya tidak yakin apakah ini jelas dalam posting saya, tetapi saya memiliki beberapa aplikasi yang bergantung pada pustaka yang sama dan saya tidak ingin menduplikasi skrip pembuatan untuk pustaka di seluruh aplikasi.
André Caron
3
Anda harus menguraikan jawaban Anda untuk menunjukkan bagaimana jawaban itu mengatasi berbagai masalah. Tidak jelas bagi saya bagaimana Anda menautkan dependensi mengingat, tergantung pada konteksnya, pustaka dependen tidak berada di lokasi yang sama.
André Caron
0

Saya tidak akan menggunakan submodula.

Ini menggoda, sama seperti dulu dengan svn-eksternal. Namun, dapatkah Anda yakin semua proyek yang Anda tautkan masih berada di tempat yang sama dalam setahun? Bagaimana dengan lima?

Oleh karena itu, saya hanya menyalin semua dependensi yang diperlukan ke proyek saya. Ini berarti bahwa selama repo saya valid, saya dapat memeriksa keadaan yang sebenarnya.

Pada dasarnya, saya memiliki struktur folder sebagai berikut:

myproject/... [sources etc]
ext/ [third-party dependencies]


e.g. ext/boost, ext/cppunit

Meskipun ini tidak terlalu bagus dari perspektif ruang disk, saya menghargai jaminan bahwa saya dapat memeriksa setiap negara yang tercatat selama repo tersedia jauh lebih tinggi.

Selain itu, ada banyak masalah dengan submodul seperti yang dijelaskan di sini

Wilbert
sumber
Saya yakin mereka ada di lokasi yang tepat karena saya memelihara semuanya :-) Juga, berhati-hatilah dalam menyalin proyek karena kondisi redistribusi.
André Caron
Oke, itu mengurangi masalah. Dan perizinan: Ya, Anda harus berhati-hati, tapi itu masalah yang sama sekali berbeda.
Wilbert
0

Menghadapi masalah yang sama persis di sini. Salah satu solusi bisa memiliki beberapa repo libsyang akan terus core, network, graphsebagai submodul dan hanya CMakeLists yang akan memberitahu setiap libs di mana untuk menemukan dependensinya. Setiap aplikasi sekarang akan memiliki libssubmodule dan hanya menggunakan lib yang diperlukan.

Pengujian setiap lib dapat diatur dalam 2 cara:

  • Memiliki core_testing, graph_testing, network_testing sebagai aplikasi terpisah
  • Menyebarkan lib yang diuji ke server-pengujian dan menemukannya saat menjalankan tes menggunakan cmake
Maks
sumber
Bukankah ini membuat semua lib tersedia untuk semua lib lainnya?
André Caron
Secara default, ya. Tapi itu bisa diputuskan dalam cmakelis level libs. Jika graphtidak perlu tahu tentang network- jangan networklewatkan hal-hal yang berhubungan dengan graphsubdir
Max