Daftar submodules dalam repositori Git

246

Saya memiliki repositori Git yang memiliki beberapa submodul di dalamnya. Bagaimana saya mendaftar nama semua submodul setelah git submodule initdijalankan?

The git submodule foreachperintah bisa menggemakan nama-nama submodule, tapi itu hanya bekerja setelah mereka telah memeriksa yang belum terjadi setelah langkah init. Ada lebih banyak langkah dalam rantai yang perlu terjadi sebelum mereka dapat diperiksa, dan saya tidak ingin harus memasukkan nama-nama submodul ke dalam skrip.

Jadi apakah ada perintah Git untuk mendapatkan semua nama yang terdaftar saat ini, tetapi belum memeriksa submodul?

tpg2114
sumber
4
Sangat konyol tidak, tetapi jawaban Sandeep menunjukkan bahwa git submoduleberperilaku seperti yang saya harapkan hipotetis git submodule listuntuk berperilaku - Saya hanya tidak pernah berpikir untuk memeriksa apa yang terjadi tanpa argumen git submodule. (Senang saya menguji tautan itu, karena saya awalnya mengambil tautan 'Bagikan' yang salah!)
bijak
4
Saya datang ke sini karena git submodule listtidak ada dan git submodule helptidak membantu (menurut yang terakhir, solusinya,, git submodulebukan penggunaan yang valid).
user2394284
Sebagian besar jawaban (termasuk yang diterima) mendaftar submodule paths, tidak namesdan pecah ketika mereka berisi karakter khusus. Saya mencoba memberikan jawaban untuk kedua nama dan jalur yang harus aman: stackoverflow.com/a/56912913/3215929
Ente

Jawaban:

175

Anda bisa menggunakan mekanisme yang sama seperti git submodule initmenggunakan itu sendiri, yaitu, lihat .gitmodules. File-file ini menyebutkan setiap jalur submodule dan URL yang dirujuk.

Misalnya, dari root repositori, cat .gitmodulesakan mencetak konten ke layar (dengan asumsi Anda punya cat).

Karena file .gitmodule memiliki format konfigurasi Git, Anda dapat menggunakan konfigurasi git untuk mem-parsing file-file tersebut:

git config --file .gitmodules --name-only --get-regexp path

Akan menampilkan semua entri submodule, dan dengan

git config --file .gitmodules --get-regexp path | awk '{ print $2 }'

Anda hanya akan mendapatkan jalur submodule itu sendiri.

Ikke
sumber
Tapi itu tidak mencetak apa pun di konsol.
IgorGanapolsky
2
@IgorGanapolsky - Anda dapat mencetak di konsol, jika Anda melakukannya cat .gitmodulesdi root repositori ...
sdaau
Bagian awkgagal jika Anda memiliki spasi di jalur submodule.
maikel
@ Ikke Saya ingin mengambil daftar submodula termasuk nama, jalur dan url. Saya mencoba perintah Git berikut, tetapi tidak mengembalikan apa-apa: git config --file = .gitmodules --get-regexp. *? Submodule (. *)] Path = (. *) Url = (. *) I mencoba git config --file = .gitmodules --get-regexp. *? (submodule). *? (path). *? (url) juga. Mungkin Anda punya solusi. Terima kasih sebelumnya.
Odrai
8
PERINGATAN: awkgagal untuk submodula dengan spasi! Perintah harus membaca git config -z --file .gitmodules --get-regexp '\.path$' | sed -nz 's/^[^\n]*\n//p' | tr '\0' '\n'(Anda perlu modern seddengan -z). Ini gagal untuk jalur dengan Newlines di dalamnya (mereka dapat dibuat dengan git mv). Jika Anda ingin aman terhadap ini, tinggalkan | tr '\0' '\n'dan gunakan sesuatu seperti ... | while IFS='' read -d '' path; do ...untuk diproses lebih lanjut dengan bash. Ini membutuhkan bash modern yang mengerti read -d ''(jangan lupa ruang antara -ddan '').
Tino
109

Anda dapat menggunakan git submodule statusatau secara opsional git submodule status --recursivejika Anda ingin menunjukkan submodula bersarang.

Dari dokumentasi Git:

Tampilkan status submodula. Ini akan mencetak SHA-1 dari commit yang saat ini diperiksa untuk setiap submodule, bersama dengan path submodule dan output dari git yang dijelaskan untuk SHA-1. Setiap SHA-1 akan diawali dengan - jika submodule tidak diinisialisasi, + jika komit submodule yang saat ini diperiksa tidak cocok dengan SHA-1 yang ditemukan dalam indeks repositori yang berisi dan U jika submodule memiliki konflik gabungan.

Jon Koops
sumber
2
Jalankan saja git submodule update --init --recursiveuntuk menginisialisasi semua submodule.
Jon Koops
2
@IgorGanapolsky baru saja membaca komentar Stefaan: perintah semacam ini tidak berfungsi jika submodules belum diinisialisasi . Tidak ada output = tidak ada submodule (daftar kosong).
Tim
6
Ini harus ditandai sebagai jawaban terbaik untuk menggunakan perintah sederhana dan gitberbasis- asli tanpa bantuan dari bash. Dan solusi ini elegan dalam cara berjalan dengan baik di setiap titik copy pekerjaan (tetapi submodula itu sendiri tentu saja, yang hasilnya langsung berlaku untuk diri mereka sendiri).
Tim
Seperti jawaban Sandeep Gill mengatakan, git submoduletanpa argumen sama dengan git submodule status, jadi Anda dapat menyelamatkan diri dengan mengetik 7 karakter ;-)
Sam
@ Sam Mereka tidak persis sama sejak git submodule status --recursivebekerja, tetapi git submodule --recursivetidak. 7 karakter itu membelikan Anda sesuatu. Itu tergantung pada kebutuhan Anda.
Kevin Rak
60

Untuk mengembalikan hanya nama-nama dari submodules terdaftar, Anda dapat menggunakan perintah ini:

grep path .gitmodules | sed 's/.*= //'

Anggap saja itu git submodule --listtidak ada.

mholm815
sumber
3
Sebagai gantinya, gunakan perl -ne '/^\s*path =\s*(.*)/ and push(@submods, $1); END { print(join("\n", sort(@submods)));}' "$(git rev-parse --show-toplevel)/.gitmodules"yang dibandingkan dengan jawaban ini (1) berfungsi dari subdirektori mana saja (meskipun tidak di dalam submodule); (2) mengurutkan submodul dengan nama; dan (3) mengabaikan baris komentar dalam .gitmodules.
Colin D Bennett
6
Dan mudah diingat untuk boot!
Dan
1
Perhatikan bahwa ini adalah cara yang sangat ceroboh untuk melakukannya, seperti yang pathmungkin ada dalam nama submodule ( git submodule add https://github.com/commercialhaskell/path.git). Tapi Anda mungkin sudah tahu itu sebelumnya. Jika Anda ingin mengakses .gitconfigdari mana saja di sebuah meja kerja atau perlu menjalankan ini di --barerepositori, Anda dapat menggunakan sesuatu seperti git cat-file -p HEAD:.gitmodules | .... Jika Anda perlu merujuk ke file "bertahap", Anda dapat melakukannya git cat-file -p :.gitmodules | ..., namun ini membutuhkan git indexuntuk hadir.
Tino
56

Perintah berikut akan mencantumkan submodul:

git submodule--helper list

Outputnya kira-kira seperti ini:

<mode> <sha1> <stage> <location>

Catatan: Ini membutuhkan Git 2.7.0 atau lebih tinggi.

DI
sumber
1
Bagus!. Di mana perintah ini didokumentasikan. Bekerja di Git untuk Windwos tetapi tidak dapat menemukan dokumen di git-scm.com
DarVar
1
git ls-files --stage | grep ^160000(dari Answer stackoverflow.com/a/29325219 ) tampaknya menghasilkan hasil yang sama, jadi mungkin ini adalah pengganti yang baik jika Anda harus kompatibel dengan yang lebih tua.
Tino
Perhatikan --garis ganda disubmodule--helper
it3xl
25

Menggunakan:

$ git submodule

Ini akan mencantumkan semua submodula dalam repositori Git yang ditentukan.

Sandeep Gill
sumber
3
Ini secara efektif jawaban duplikat dari dua jawaban lain yang menyebutkan git submodule [status](catatan yang statustersirat jika dihilangkan, jadi ini sama).
Colin D Bennett
Tidak selalu berhasil. fatal: no submodule mapping found in .gitmodules for path 'bla-bla/foo-bar'. Pertama, Anda harus menghapus semua repositori dalam yang belum dikirim.
it3xl
1
Jawaban terbaik (• ̀ ω • ́) ✧
Răzvan Flavius ​​Panda
Perhatikan bahwa jika Anda ingin menggunakan --recursiveflag, Anda harus secara eksplisit menambahkan statusperintah: git submodule status --recursiveberfungsi, tetapi git submodule --recursivetidak.
Sam
17

Saya menggunakan ini:

git config --list|egrep ^submodule
Robert Sjödahl
sumber
1
@IgorGanapolsky baru saja membaca komentar Stefaan: Ini tidak berfungsi jika submodule belum diinisialisasi . Tidak ada output = tidak ada submodule (daftar kosong).
Tim
Ini adalah apa yang saya butuhkan. Ini menunjukkan subfolder dari submodules dan url dari remote mereka.
thinsoldier
17

Saya perhatikan bahwa perintah yang diberikan dalam jawaban untuk pertanyaan ini memberi saya informasi yang saya cari:

Tidak ditemukan pemetaan submodule di .gitmodule untuk jalur yang bukan submodule

git ls-files --stage | grep 160000
Max Cantor
sumber
Jawaban ini bagus dan bersih, adakah kerugian dibandingkan dengan jawaban mholm815 yang menguraikan .gitmodules ?
Colin D Bennett
BTW, jika Anda hanya ingin nama-nama submodula, gunakangit ls-files --stage | grep 160000 | perl -ne 'chomp;split;print "$_[3]\n"'
Colin D Bennett
Ini bekerja untuk saya karena saya tidak punya .gimodulesatau apa pun di dalamnya .git/config. (Saya tidak yakin bagaimana hal itu terjadi, saya mendapat repositori dalam keadaan ini. Itu adalah beberapa kesalahan, jadi solusinya adalah git rm.)
wenzeslaus
1
Ini bekerja dengan repo kosong. Tidak seperti solusi .gitmodules.
kupson
1
Ini jawaban terbaik. Hanya sedikit nit: grep "^160000 "akan sedikit lebih kuat.
Lassi
12

Jika Anda tidak keberatan beroperasi hanya pada submodules yang diinisialisasi, Anda dapat menggunakan git submodule foreachuntuk menghindari penguraian teks.

git submodule foreach --quiet 'echo $name'
Benesch
sumber
1
Jawaban ini unik karena hanya berfungsi untuk submodul yang telah diinisialisasi. Bergantung pada apa yang Anda butuhkan, ini mungkin perilaku yang diinginkan (tetapi mungkin juga tidak terduga dan tidak diinginkan.)
Seth Johnson
9

Kamu bisa memakai:

git submodule | awk '{ print $2 }'
fabceolin
sumber
1
Ini tampaknya menghasilkan output yang sama dengan stackoverflow.com/a/23490756/895245 tetapi lebih pendek.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
Diturunkan. Perintah ini berbahaya, karena gagal untuk submodule bernama iE test (master)(nama dengan spasi diikuti oleh tanda kurung), yang merupakan nama submodule yang valid . Perintah juga tidak dapat diperbaiki, karena git mencetak moduleatau module (branch). Dan itu bahkan lebih buruk, karena perintah ini tidak porcellain, sehingga output dari perintah dapat berubah di masa depan tanpa pemberitahuan sebelumnya.
Tino
7

Saya menggunakan ini:

git submodule status | cut -d' ' -f3-4 

Output (jalur + versi):

tools/deploy_utils (0.2.4)
Skarab
sumber
Kerugian yang saya lihat dari versi ini adalah lambat. Tampaknya melakukan semacam pengecekan status pada setiap submodule, mungkin hampir satu detik per submodule di komputer saya, jadi pada proyek dengan banyak submodul ini bukan solusi yang baik, atau jika harus dijalankan dari skrip dll.
Colin D Bennett
7

Untuk membuat daftar semua submodul dengan nama:

git submodule --quiet foreach --recursive 'echo $name'

bGorle
sumber
7

Ini bekerja untuk saya:

git ls-files --stage | grep ^160000

Ini didasarkan pada artikel hebat ini: Memahami Submodules Git

Itu harus membaca grep ^160000.

LTK
sumber
1
git ls-files --stage | grep ^160000tampaknya menghasilkan output yang sama seperti git submodule--helper listdari answer stackoverflow.com/a/40877379
Tino
5

Hanya satu jalur submodule menyenangkan, Bu ...

git config --list | grep \^submodule | cut -f 2 -d .
Vendor/BaseModel
Vendor/ObjectMatcher
Vendor/OrderedDictionary
Vendor/_ObjC
Vendor/XCodeHelpers

👍🏼

Alex Gray
sumber
4
Walaupun ini mungkin jawaban yang benar-benar valid untuk pertanyaan ini, berikut adalah beberapa peringatan: Ini hanya berfungsi untuk submodul yang tidak mengandung titik-titik atas namanya. Sebuah titik benar-benar valid dalam nama modul. Itu tidak terbatas pada .urlkunci, sehingga entri lain mungkin muncul juga (biasanya tidak ada, tapi omong kosong terjadi). Anda harus menggunakan di --localsini, karena Anda tidak ingin melihat --globaldan --systempengaturan. Dan yang terakhir untuk dicatat, karena mungkin diabaikan, itu hanya berfungsi untuk submodul, yang sudah ada di .git/config(seperti setelah git submodule init, lihat pertanyaan).
Tino
5

git configmemungkinkan untuk menentukan file konfigurasi.
Dan .gitmodules merupakan file konfigurasi.

Jadi, dengan bantuan " gunakan ruang sebagai pembatas dengan perintah cut ":

git config --file=.gitmodules --get-regexp ^^submodule.*\.path$ | cut -d " " -f 2

Itu hanya akan mencantumkan path, satu per submodule yang dideklarasikan.

Seperti yang ditunjukkan Tino dalam komentar :

  • Ini gagal untuk submodula dengan spasi di dalamnya.
  • jalur submodule dapat berisi baris baru , seperti pada

    git submodule add https://github.com/hilbix/bashy.git "sub module"
      git mv 'sub module' $'sub\nmodule'
    

Sebagai alternatif yang lebih kuat, Tino mengusulkan:

git config -z --file .gitmodules --get-regexp '\.path$' | \
  sed -nz 's/^[^\n]*\n//p' | \
  tr '\0' '\n' 

Untuk jalur dengan baris baru di dalamnya (dapat dibuat dengan git mv), tinggalkan | tr '\0' '\n'dan gunakan sesuatu seperti ... | while IFS='' read -d '' path; do ...untuk diproses lebih lanjut dengan bash.
Ini membutuhkan bash modern yang mengerti read -d ''(jangan lupa ruang di antara -d and '').

VONC
sumber
hmmm ... "pasti ada cara yang lebih baik" adalah pikiran langsung saya
arcseldon
kira saya bisa alias perintah itu di profil bash dll terima kasih.
arcseldon
Ini gagal untuk submodula dengan spasi di dalamnya. Perhatikan juga bahwa jalur tersebut mungkin berisi Baris Baru ( git submodule add https://github.com/hilbix/bashy.git "sub module"; git mv 'sub module' $'sub\nmodule'). Lihat komentar saya untuk jawaban yang diterima yang sangat mirip dengan Anda.
Tino
@Tino Poin bagus. Saya telah memasukkan komentar Anda dalam jawaban untuk lebih banyak visibilitas.
VonC
3

Dalam versi Git saya [1] , setiap submisi Git memiliki a namedan a path. Mereka tidak harus sama [2] . Mendapatkan keduanya dengan cara yang andal, tanpa memeriksa submodul terlebih dahulu (git update --init ), adalah sedikit trik shell yang sulit.

Dapatkan daftar submodule names

Saya tidak menemukan cara bagaimana mencapai ini menggunakan perintah git configapa pun git. Karenanya kita kembali ke regex on .gitmodules(super jelek). Tetapi tampaknya agak aman karena gitmembatasi ruang kode yang dimungkinkan untuk submodule names. Selain itu, karena Anda mungkin ingin menggunakan daftar ini untuk pemrosesan shell lebih lanjut, solusi di bawah entri yang terpisah dengan NULL-bytes ( \0).

$ sed -nre \
  's/^\[submodule \"(.*)\"]$/\1\x0/p' \
  "$(git rev-parse --show-toplevel)/.gitmodules" \
| tr -d '\n' \
| xargs -0 -n1 printf "%b\0"

Dan dalam skrip Anda:

#!/usr/bin/env bash

while IFS= read -rd '' submodule_name; do
  echo submodule name: "${submodule_name}"
done < <(
  sed -nre \
    's/^\[submodule \"(.*)\"]$/\1\x0/p' \
    "$(git rev-parse --show-toplevel)/.gitmodules" \
  | tr -d '\n' \
  | xargs -0 -n1 printf "%b\0"
)

Catatan : read -rd ''membutuhkan bashdan tidak akan bekerja dengan sh.

Dapatkan daftar submodule paths

Dalam pendekatan saya saya mencoba tidak untuk memproses output dari git config --get-regexpdengan awk, tr, sed, ... melainkan lulus nol byte dipisahkan kembali ke git config --get. Ini untuk menghindari masalah dengan baris baru, spasi dan karakter khusus lainnya (misalnya Unicode) dalam submodule paths. Selain itu, karena Anda mungkin ingin menggunakan daftar ini untuk pemrosesan shell lebih lanjut, solusi di bawah entri yang terpisah dengan NULL-bytes ( \0).

$ git config --null --file .gitmodules --name-only --get-regexp '\.path$' \
| xargs -0 -n1 git config --null --file .gitmodules --get

Misalnya, dalam skrip Bash, Anda dapat:

#!/usr/bin/env bash

while IFS= read -rd '' submodule_path; do
  echo submodule path: "${submodule_path}"
done < <(
  git config --null --file .gitmodules --name-only --get-regexp '\.path$' \
  | xargs -0 -n1 git config --null --file .gitmodules --get
)

Catatan : read -rd ''membutuhkan bashdan tidak akan bekerja dengan sh.


Catatan kaki

[1] Versi Git

$ git --version
git version 2.22.0

[2] Submodule dengan divergingname danpath

Siapkan repositori tes:

$ git init test-name-path
$ cd test-name-path/
$ git checkout -b master
$ git commit --allow-empty -m 'test'
$ git submodule add ./ submodule-name
Cloning into '/tmp/test-name-path/submodule-name'...
done.
$ ls
submodule-name

$ cat .gitmodules
[submodule "submodule-name"]
    path = submodule-name
    url = ./

Pindahkan submodule untuk membuat namedan pathmenyimpang:

$ git mv submodule-name/ submodule-path

$ ls
submodule-path

$ cat .gitmodules
[submodule "submodule-name"]
    path = submodule-path
    url = ./

$ git config --file .gitmodules --get-regexp '\.path$'
submodule.submodule-name.path submodule-path

Pengujian

Siapkan repositori tes:

$ git init test
$ cd test/
$ git checkout -b master
$ git commit --allow-empty -m 'test'
$
$ git submodule add ./ simplename
Cloning into '/tmp/test/simplename'...
done.
$
$ git submodule add ./ 'name with spaces'
Cloning into '/tmp/test/name with spaces'...
done.
$
$ git submodule add ./ 'future-name-with-newlines'
Cloning into '/tmp/test/future-name-with-newlines'...
done.
$ git mv future-name-with-newlines/ 'name
> with
> newlines'
$
$ git submodule add ./ 'name-with-unicode-💩'
Cloning into '/tmp/test/name-with-unicode-💩'...
done.
$
$ git submodule add ./ sub/folder/submodule
Cloning into '/tmp/test/sub/folder/submodule'...
done.
$
$ git submodule add ./ name.with.dots
Cloning into '/tmp/test/name.with.dots'...
done.
$
$ git submodule add ./ 'name"with"double"quotes'
Cloning into '/tmp/test/name"with"double"quotes'...
done.
$
$ git submodule add ./ "name'with'single'quotes"
Cloning into '/tmp/test/name'with'single'quotes''...
done.
$ git submodule add ./ 'name]with[brackets'
Cloning into '/tmp/test/name]with[brackets'...
done.
$ git submodule add ./ 'name-with-.path'
Cloning into '/tmp/test/name-with-.path'...
done.

.gitmodules:

[submodule "simplename"]
    path = simplename
    url = ./
[submodule "name with spaces"]
    path = name with spaces
    url = ./
[submodule "future-name-with-newlines"]
    path = name\nwith\nnewlines
    url = ./
[submodule "name-with-unicode-💩"]
    path = name-with-unicode-💩
    url = ./
[submodule "sub/folder/submodule"]
    path = sub/folder/submodule
    url = ./
[submodule "name.with.dots"]
    path = name.with.dots
    url = ./
[submodule "name\"with\"double\"quotes"]
    path = name\"with\"double\"quotes
    url = ./
[submodule "name'with'single'quotes"]
    path = name'with'single'quotes
    url = ./
[submodule "name]with[brackets"]
    path = name]with[brackets
    url = ./
[submodule "name-with-.path"]
    path = name-with-.path
    url = ./

Dapatkan daftar submodule names

$ sed -nre \
  's/^\[submodule \"(.*)\"]$/\1\x0/p' \
  "$(git rev-parse --show-toplevel)/.gitmodules" \
| tr -d '\n' \
| xargs -0 -n1 printf "%b\0" \
| xargs -0 -n1 echo submodule name:
submodule name: simplename
submodule name: name with spaces
submodule name: future-name-with-newlines
submodule name: name-with-unicode-💩
submodule name: sub/folder/submodule
submodule name: name.with.dots
submodule name: name"with"double"quotes
submodule name: name'with'single'quotes
submodule name: name]with[brackets
submodule name: name-with-.path

Dapatkan daftar submodule paths

$ git config --null --file .gitmodules --name-only --get-regexp '\.path$' \
| xargs -0 -n1 git config --null --file .gitmodules --get \
| xargs -0 -n1 echo submodule path:
submodule path: simplename
submodule path: name with spaces
submodule path: name
with
newlines
submodule path: name-with-unicode-💩
submodule path: sub/folder/submodule
submodule path: name.with.dots
submodule path: name"with"double"quotes
submodule path: name'with'single'quotes
submodule path: name]with[brackets
submodule path: name-with-.path
Ente
sumber
0

Jika tidak ada .gitmodulesfile, tetapi konfigurasi submodul ada di .git/modules/:

find .git/modules/ -name config -exec grep url {} \;
MrSwed
sumber
0

Berikut adalah cara lain untuk mem-parsing nama-nama submodule Git dari .gitmodules tanpa memerlukan pengaturan IFS. :-)

#!/bin/env bash

function stripStartAndEndQuotes {
  temp="${1%\"}"
  temp="${temp#\"}"
  echo "$temp"
}

function getSubmoduleNames {
  line=$1
  len=${#line} # Get line length
  stripStartAndEndQuotes "${line::len-1}" # Remove last character
}

while read line; do
  getSubmoduleNames "$line"
done < <(cat .gitmodules | grep "\[submodule.*\]" | cut -d ' ' -f 2-)
devC0de
sumber
Plus, solusi ini tampaknya menangani contoh tanda kutip ganda yang diloloskan dengan benar sedangkan solusi di atas menghasilkan output yang lolos. Yang mungkin tidak benar dalam beberapa kasus. ;-)
devC0de
"di atas" dan "di bawah" tidak benar-benar berfungsi dalam urutan semacam ini.
Ente