Cara mudah untuk menarik submodula terbaru dari semua git

1847

Kami menggunakan git submodules untuk mengelola beberapa proyek besar yang memiliki ketergantungan pada banyak perpustakaan lain yang telah kami kembangkan. Setiap perpustakaan adalah repo terpisah yang dibawa ke proyek dependen sebagai submodule. Selama pengembangan, kita sering ingin mengambil versi terbaru dari setiap submodule yang bergantung.

Apakah git memiliki perintah bawaan untuk melakukan ini? Jika tidak, bagaimana dengan file batch Windows atau sejenisnya yang dapat melakukannya?

Brad Robinson
sumber
git-deep akan membantu ini.
Mathew Kurian
9
@Brad apakah Anda ingin memperbarui salinan submodul ke komit yang disebutkan dalam proyek master; atau Anda ingin menarik komit HEAD terbaru dari setiap submodule? Sebagian besar jawaban di sini membahas yang pertama; banyak orang menginginkan yang terakhir.
chrisinmtown

Jawaban:

2465

Jika ini adalah pertama kalinya Anda check-out repo, Anda perlu menggunakan --initdulu:

git submodule update --init --recursive

Untuk git 1.8.2 atau lebih tinggi, opsi --remotetelah ditambahkan untuk mendukung pembaruan ke tips terbaru dari cabang jarak jauh:

git submodule update --recursive --remote

Ini memiliki manfaat tambahan untuk menghormati cabang "non default" yang ditentukan dalam file .gitmodulesatau .git/config(jika Anda kebetulan punya, default adalah asal / master, dalam hal ini beberapa jawaban lain di sini akan bekerja juga).

Untuk git 1.7.3 atau lebih baru, Anda dapat menggunakan (tetapi gotchas di bawah tentang pembaruan apa yang masih berlaku):

git submodule update --recursive

atau:

git pull --recurse-submodules

jika Anda ingin menarik submodul Anda ke commit terbaru alih-alih komit saat ini, arahkan ke.

Lihat git-submodule (1) untuk detailnya

Henrik Gustafsson
sumber
299
Mungkin Anda harus menggunakannya git submodule update --recursivesaat ini.
Jens Kohl
38
Peningkatan kinerja:git submodule foreach "(git checkout master; git pull)&"
Bogdan Gusiev
18
pembaruan akan memperbarui setiap submodule ke revisi yang ditentukan, bukan memperbaruinya ke yang terbaru untuk repositori itu.
Peter DeWeese
21
Hanya untuk menambahkan, menempel secara membuta origin masterdi akhir perintah ini mungkin memiliki hasil yang tidak terduga jika beberapa submodula Anda melacak cabang atau nama lokasi yang berbeda dari submodule tertentu. Jelas bagi sebagian orang, tetapi mungkin tidak bagi semua orang.
Nathan Hornby
31
Hanya untuk memperjelas bagi semua orang. git submodule update --recursiveterlihat untuk melihat revisi mana repositori induk telah disimpan untuk setiap submodule, kemudian memeriksa revisi itu di setiap submodule. Ini TIDAK menarik komit terbaru untuk setiap submodule. git submodule foreach git pull origin masteratau git pull origin master --recurse-submodulesapa yang Anda inginkan jika Anda ingin memperbarui setiap submodule ke yang terbaru dari repositori asalnya. Hanya dengan demikian Anda akan mendapatkan perubahan yang tertunda dalam repo induk dengan hash revisi yang diperbarui untuk submodul. Periksa itu dan Anda baik-baik saja.
Chev
636
git pull --recurse-submodules --jobs=10

sebuah fitur git yang pertama kali dipelajari pada 1.8.5.

Sampai bug diperbaiki, untuk pertama kali Anda perlu menjalankannya

git submodule update --init --recursive

Alexander Bartosh
sumber
29
terbalik, saya menggunakan ini: alias update_submodules = 'git pull --recurse-submodules && git submodule update'
Stephen C
3
Ini berfungsi jika submodul sudah ditarik setidaknya sekali tetapi untuk submodul yang belum pernah diperiksa, lihat jawaban gahooa di bawah ini.
Matt Browne
8
Ini akan menarik ke versi repo atas menentukan; itu TIDAK menarik KEPALA. Misalnya jika TopRepo menentukan versi 2 di belakang HEAD untuk SubRepo, ini akan menarik SubRepo dengan versi yang tertinggal 2. Jawaban lain di sini tarik KEPALA di SubRepo.
Chris Moschini
11
Catatan bahwa baik git pull --recurse-submodulesatau git submodule update --recursivetidak tidak initialize baru submodul menambahkan. Untuk menginisialisasi mereka, Anda perlu menjalankan git submodule update --recursive --init. Kutipan dari manual : Jika submodule belum diinisialisasi, dan Anda hanya ingin menggunakan pengaturan seperti yang tersimpan di .gitmodules, Anda dapat secara otomatis menginisialisasi submodule dengan opsi --init.
patryk.beza
1
mungkin menambahkan petunjuk git submodule update --recursive --remoteyang juga memperbarui submodules ke revisi terbaru jarak jauh alih-alih SHA-1 yang disimpan.
Hanno S.
386

Pada init menjalankan perintah berikut:

git submodule update --init --recursive

dari dalam direktori git repo, yang terbaik untuk saya.

Ini akan menarik semua submodula terbaru termasuk.

Dijelaskan

git - the base command to perform any git command
    submodule - Inspects, updates and manages submodules.
        update - Update the registered submodules to match what the superproject
        expects by cloning missing submodules and updating the working tree of the
        submodules. The "updating" can be done in several ways depending on command
        line options and the value of submodule.<name>.update configuration variable.
            --init without the explicit init step if you do not intend to customize
            any submodule locations.
            --recursive is specified, this command will recurse into the registered
            submodules, and update any nested submodules within.

Setelah ini, Anda bisa menjalankan:

git submodule update --recursive

dari dalam direktori git repo, yang terbaik untuk saya.

Ini akan menarik semua submodula terbaru termasuk.

abc123
sumber
10
Ya - jawaban pilihan tertinggi adalah cara terbaik untuk melakukannya di '09, tapi ini jelas lebih sederhana dan lebih intuitif sekarang.
Michael Scott Cuthbert
2
@MichaelScottCuthbert terima kasih, saya yakin dalam 3 tahun lagi perintah ini akan menjadi gila juga
abc123
5
Namun demikian, ini tidak mengecualikan revisi terbaru dari submodule, hanya revisi terbaru yang dilacak induknya.
Nathan Osman
4
@NathanOsman yang Anda inginkan ... Anda akan mendapatkan kode yang rusak dengan tidak mengikuti pelacakan revisi orang tua. Jika Anda adalah pengelola dari orang tua Anda dapat memperbaruinya sendiri dan komit.
abc123
2
Ya, tapi dari pemahaman saya, bukan itu yang diinginkan OP.
Nathan Osman
305

Catatan: Ini dari 2009 dan mungkin bagus tetapi ada pilihan yang lebih baik sekarang.

Kami menggunakan ini. Disebut git-pup:

#!/bin/bash
# Exists to fully update the git repo that you are sitting in...

git pull && git submodule init && git submodule update && git submodule status

Masukkan saja ke direktori bin yang sesuai (/ usr / local / bin). Jika pada Windows, Anda mungkin perlu memodifikasi sintaks untuk membuatnya bekerja :)

Memperbarui:

Menanggapi komentar oleh penulis asli tentang menarik semua KEPALA semua submodula - itu adalah pertanyaan yang bagus.

Saya cukup yakin bahwa gittidak memiliki perintah untuk ini secara internal. Untuk melakukannya, Anda perlu mengidentifikasi apa sebenarnya HEAD untuk submodule. Itu bisa sesederhana seperti mengatakan masteradalah cabang yang paling up to date, dll ...

Setelah ini, buat skrip sederhana yang melakukan hal berikut:

  1. periksa git submodule statusrepositori "yang dimodifikasi". Karakter pertama dari garis keluaran menunjukkan ini. Jika sub-repo diubah, Anda mungkin TIDAK ingin melanjutkan.
  2. untuk setiap repo yang terdaftar, masukkan ke direktori itu dan jalankan git checkout master && git pull. Periksa kesalahan.
  3. Pada akhirnya, saya sarankan Anda mencetak tampilan kepada pengguna untuk menunjukkan status submodul saat ini - mungkin meminta mereka untuk menambahkan semua dan melakukan?

Saya ingin menyebutkan bahwa gaya ini sebenarnya bukan untuk apa git submodules dirancang. Biasanya, Anda ingin mengatakan "LibraryX" ada di versi "2.32" dan akan tetap seperti itu sampai saya kirim ke "upgrade".

Artinya, dalam arti tertentu, apa yang Anda lakukan dengan skrip yang dijelaskan, tetapi hanya secara otomatis. Diperlukan perawatan!

Pembaruan 2:

Jika Anda berada di platform windows, Anda mungkin ingin melihat menggunakan Python untuk mengimplementasikan skrip karena sangat mampu di bidang ini. Jika Anda menggunakan unix / linux, maka saya sarankan hanya bash script.

Perlu klarifikasi? Cukup kirim komentar.

gahooa
sumber
Saya tidak berpikir itu yang saya inginkan. Tidakkah itu akan menarik versi submodul yang super-proyek terakhir kali berkomitmen dengannya. Saya ingin menarik versi kepala dari semua submodules.
Brad Robinson
3
Ini berfungsi dengan baik, dan bekerja tidak hanya untuk memperbarui submodules tetapi juga untuk mengambilnya untuk pertama kalinya jika itu yang Anda butuhkan.
Matt Browne
Saya baru mendapatkan, "Tidak ada informasi pelacakan untuk cabang saat ini. Silakan tentukan cabang mana yang ingin Anda gabungkan." Tidak peduli apa yang saya coba: /
Nathan Hornby
9
Mengapa tidak membuat alias untuk itu? git config --global alias.pup '!git pull && git submodule init && git submodule update && git submodule status'dan kemudian menggunakannya git puptanpa skrip.
fracz
Terima kasih, untuk beberapa alasan walaupun saya memiliki git 1.9.1 saya harus tampil git submodule init setelah tarikan pertama yang menyertakan submodul, sehingga semuanya akan mulai berfungsi dengan baik.
Ben Usman
164

Henrik ada di jalur yang benar. Perintah 'foreach' dapat menjalankan skrip shell sembarang. Dua opsi untuk menarik yang terbaru mungkin,

git submodule foreach git pull origin master

dan,

git submodule foreach /path/to/some/cool/script.sh

Itu akan beralih melalui semua submodules diinisialisasi dan menjalankan perintah yang diberikan.

mturquette
sumber
144

Berikut ini bekerja untuk saya di Windows.

git submodule init
git submodule update
zachleat
sumber
6
Ini jelas bukan yang diminta OP. Ini hanya akan memperbarui ke submodule terkait yang melakukan dan bukan yang terbaru.
Patrick
52
Namun ini adalah satu-satunya hal di halaman ini yang mendapat git untuk menarik submodules saat pertama kali saya memeriksa repo
theheadofabroom
2
Dapat juga menggunakan: git submodule update --init --recursive (terutama jika submodule yang dimaksud adalah RestKit dari klon baru)
HCdev
33

Edit :

Dalam komentar itu ditunjukkan (oleh philfreo ) bahwa versi terbaru diperlukan. Jika ada submodula bersarang yang perlu dalam versi terbaru mereka:

git submodule foreach --recursive git pull

----- Komentar ketinggalan jaman di bawah ini -----

Bukankah ini cara resmi untuk melakukannya?

git submodule update --init

Saya menggunakannya setiap waktu. Tidak ada masalah sejauh ini.

Edit:

Saya baru saja menemukan bahwa Anda dapat menggunakan:

git submodule foreach --recursive git submodule update --init 

Yang juga akan menarik semua submodul secara rekursif, yaitu ketergantungan.

bersifat antitoksin
sumber
5
Jawaban Anda tidak menjawab pertanyaan OP, tetapi untuk melakukan apa yang telah Anda usulkan, Anda bisa katakangit submodule update --init --recursive
philfreo
2
Begitu ya, versi terbaru diperlukan. Nah ini mungkin berguna jika ada submodules bersarang: git submodule foreach --recursive git pull
antitoxic
1
Saya tidak dapat membuat salah satu dari ini benar-benar mengunduh apa pun - "git submodule update --init --recursive" bekerja untuk saya.
BrainSlugs83
33

Seperti yang mungkin terjadi bahwa cabang default dari submodules Anda tidak master , ini adalah bagaimana saya mengotomatiskan upgrade submodules Git lengkap:

git submodule init
git submodule update
git submodule foreach 'git fetch origin; git checkout $(git rev-parse --abbrev-ref HEAD); git reset --hard origin/$(git rev-parse --abbrev-ref HEAD); git submodule update --recursive; git clean -dfx'
Sebastien Varrette
sumber
dari banyak jawaban untuk banyak pertanyaan, yang ini bekerja untuk saya (2019, kesalahan github dengan id hash tertentu)
philshem
30

Pertama kali

Submodule Klon dan Init

git clone [email protected]:speedovation/kiwi-resources.git resources
git submodule init

Beristirahat

Selama pengembangan, cukup tarik dan perbarui submodule

git pull --recurse-submodules  && git submodule update --recursive

Perbarui submit Git ke komit terbaru asal

git submodule foreach git pull origin master

Cara yang disukai harus di bawah

git submodule update --remote --merge

catatan: dua perintah terakhir memiliki perilaku yang sama

Yash
sumber
Saya melakukan klon git tanpa kesalahan submodule dan semua opsi lain tidak berhasil, tidak ada yang mengkloning submodules. Menggunakan milikmu, git submodule updatelakukan triknya. Sekarang saya mengunduh data submodul yang hilang dari langkah pertama klon. Terima kasih. Saya tidak pandai git: C
m3nda
Anser ini sebenarnya merupakan jawaban yang sangat baik untuk mengajukan pertanyaan di sini di atas: mengapa saya harus ".. - submodules-rekursif .." dan kemudian "... pembaruan ..." dan bahkan ".. .setiap ... "nanti untuk mendapatkan komit terbaru? Semua ini tidak terlihat seperti GIT sama sekali! Apa yang dilakukan "pembaruan" dan mengapa saya harus secara manual pergi ke setiap modul untuk menarik? Bukankah itu yang dilakukan "... - kiriman ulang ..." Ada petunjuk?
Peter Branforn
20

Saya tidak tahu karena versi git mana ini berfungsi, tapi itulah yang Anda cari:

git submodule update --recursive

Saya menggunakannya git pulluntuk memperbarui repositori root, juga:

git pull && git submodule update --recursive
Jens Kohl
sumber
10

Jawaban di atas bagus, namun kami menggunakan git-hooks untuk mempermudah ini tetapi ternyata di git 2.14 , Anda dapat mengatur git config submodule.recursetrue untuk mengaktifkan submodules untuk diperbarui ketika Anda menarik ke repositori git Anda.

Ini akan memiliki efek samping dari mendorong semua perubahan submodul yang Anda miliki jika ada di cabang, tetapi jika Anda sudah membutuhkan perilaku itu maka ini bisa melakukan pekerjaan.

Dapat dilakukan dengan menggunakan:

git config submodule.recurse true
JamesD
sumber
Harus menyukai opsi ini, sayangnya masih perlu digunakan git submodule initsebelumnya meskipun jika submodule Anda belum diinisialisasi.
Pellet
5

Git untuk windows 2.6.3 :

git submodule update --rebase --remote

seoul
sumber
Itu satu-satunya yang bekerja untuk saya. Saya bahkan tidak dapat init atau memperbarui karena pointer submodule menunjuk ke versi yang tidak lagi di remote
Pavel P
4

Dari tingkat atas dalam repo:

git submodule foreach git checkout develop
git submodule foreach git pull

Ini akan mengalihkan semua cabang untuk mengembangkan dan menarik terbaru

Srayan Guhathakurta
sumber
2
Tidak bekerja untuk saya, dengan git 2.7.
Bruno Haible
Apakah Anda memiliki sesuatu seperti file Everything sln yang menambahkan semua referensi proyek di pohon? Juga kesalahan apa yang Anda lihat? Bisakah Anda memeriksa file gitignore Anda juga
Srayan Guhathakurta
1
git submodule foreach git pull origin masterHarus menambahkan cabang yang ingin saya ambil. selain itu, bekerja dengan sempurna.
Torxed
3

Saya melakukan ini dengan mengadaptasi jawaban gahooa di atas :

Padukan dengan git [alias]...

Jika proyek induk Anda memiliki sesuatu seperti ini di .gitmodules:

[submodule "opt/submodules/solarized"]
    path = opt/submodules/solarized
    url = [email protected]:altercation/solarized.git
[submodule "opt/submodules/intellij-colors-solarized"]
    path = opt/submodules/intellij-colors-solarized
    url = [email protected]:jkaving/intellij-colors-solarized.git

Tambahkan sesuatu seperti ini di dalam .gitconfig Anda

[alias]
    updatesubs = "!sh -c \"git submodule init && git submodule update && git submodule status\" "

Kemudian untuk memperbarui submodula Anda, jalankan:

git updatesubs

Saya punya contoh di repo pengaturan lingkungan saya .

Tom
sumber
3

Yang perlu Anda lakukan sekarang adalah sederhana git checkout

Pastikan untuk mengaktifkannya melalui konfigurasi global ini: git config --global submodule.recurse true

Pelet
sumber
2

Berikut ini adalah baris perintah untuk menarik dari semua repositori git Anda, apakah itu submodules atau tidak:

ROOT=$(git rev-parse --show-toplevel 2> /dev/null)
find "$ROOT" -name .git -type d -execdir git pull -v ';'

Jika Anda berjalan di atas git repositori Anda, Anda dapat mengganti "$ROOT"ke ..

kenorb
sumber
1

Saya pikir Anda harus menulis skrip untuk melakukan ini. Sejujurnya, saya mungkin menginstal python untuk melakukannya sehingga Anda dapat menggunakan os.walkuntuk cdke setiap direktori dan mengeluarkan perintah yang sesuai. Menggunakan python atau bahasa skrip lain, selain batch, akan memungkinkan Anda untuk dengan mudah menambah / menghapus sub proyek tanpa harus memodifikasi skrip.

baudtack
sumber
1

Komentar: cara yang tidak terlalu mudah, tetapi bisa diterapkan dan memiliki kelebihan yang unik.

Jika seseorang ingin mengkloning hanya HEADrevisi dari repositori dan hanya HEADs dari semua submodulenya (yaitu untuk checkout "trunk"), maka seseorang dapat menggunakan skrip Lua berikut . Terkadang perintah sederhana git submodule update --init --recursive --remote --no-fetch --depth=1dapat menghasilkan gitkesalahan yang tidak dapat dipulihkan . Dalam hal ini kita perlu membersihkan subdirektori dari .git/modulesdirektori dan mengklon submodule secara manual menggunakan git clone --separate-git-dirperintah. Satu-satunya kompleksitas adalah untuk mengetahui URL , jalur .gitdirektori submodule dan jalur submodule di pohon superproject.

Catatan: skrip hanya diuji terhadap https://github.com/boostorg/boost.gitrepositori. Keunikannya: semua submodules dihosting di host yang sama dan .gitmoduleshanya berisi URL relatif .

-- mkdir boost ; cd boost ; lua ../git-submodules-clone-HEAD.lua https://github.com/boostorg/boost.git .
local module_url = arg[1] or 'https://github.com/boostorg/boost.git'
local module = arg[2] or module_url:match('.+/([_%d%a]+)%.git')
local branch = arg[3] or 'master'
function execute(command)
    print('# ' .. command)
    return os.execute(command)
end
-- execute('rm -rf ' .. module)
if not execute('git clone --single-branch --branch master --depth=1 ' .. module_url .. ' ' .. module) then
    io.stderr:write('can\'t clone repository from ' .. module_url .. ' to ' .. module .. '\n')
    return 1
end
-- cd $module ; git submodule update --init --recursive --remote --no-fetch --depth=1
execute('mkdir -p ' .. module .. '/.git/modules')
assert(io.input(module .. '/.gitmodules'))
local lines = {}
for line in io.lines() do
    table.insert(lines, line)
end
local submodule
local path
local submodule_url
for _, line in ipairs(lines) do
    local submodule_ = line:match('^%[submodule %"([_%d%a]-)%"%]$')
    if submodule_ then
        submodule = submodule_
        path = nil
        submodule_url = nil
    else
        local path_ = line:match('^%s*path = (.+)$')
        if path_ then
            path = path_
        else
            submodule_url = line:match('^%s*url = (.+)$')
        end
        if submodule and path and submodule_url then
            -- execute('rm -rf ' .. path)
            local git_dir = module .. '/.git/modules/' .. path:match('^.-/(.+)$')
            -- execute('rm -rf ' .. git_dir)
            execute('mkdir -p $(dirname "' .. git_dir .. '")')
            if not execute('git clone --depth=1 --single-branch --branch=' .. branch .. ' --separate-git-dir ' .. git_dir .. ' ' .. module_url .. '/' .. submodule_url .. ' ' .. module .. '/' .. path) then
                io.stderr:write('can\'t clone submodule ' .. submodule .. '\n')
                return 1
            end
            path = nil
            submodule_url = nil
        end
    end
end
Tomilov Anatoliy
sumber