Git alt modülünü en son başlangıç ​​noktasında güncelleyin


853

Git alt modülüne sahip bir projem var. Bu bir ssh: // ... URL'sinden ve A taahhüdünde. Komut B bu URL'ye aktarıldı ve alt modülün taahhüdü almasını ve URL'de değişmesini istiyorum.

Şimdi, benim anlayışım git submodule updatebunu yapmalı ama öyle değil. Hiçbir şey yapmaz (çıktı yok, başarı çıkış kodu). İşte bir örnek:

$ mkdir foo
$ cd foo
$ git init .
Initialized empty Git repository in /.../foo/.git/
$ git submodule add ssh://user@host/git/mod mod
Cloning into mod...
user@host's password: hunter2
remote: Counting objects: 131, done.
remote: Compressing objects: 100% (115/115), done.
remote: Total 131 (delta 54), reused 0 (delta 0)
Receiving objects: 100% (131/131), 16.16 KiB, done.
Resolving deltas: 100% (54/54), done.
$ git commit -m "Hello world."
[master (root-commit) 565b235] Hello world.
 2 files changed, 4 insertions(+), 0 deletions(-)
 create mode 100644 .gitmodules
 create mode 160000 mod
# At this point, ssh://user@host/git/mod changes; submodule needs to change too.
$ git submodule init
Submodule 'mod' (ssh://user@host/git/mod) registered for path 'mod'
$ git submodule update
$ git submodule sync
Synchronizing submodule url for 'mod'
$ git submodule update
$ man git-submodule 
$ git submodule update --rebase
$ git submodule update
$ echo $?
0
$ git status
# On branch master
nothing to commit (working directory clean)
$ git submodule update mod
$ ...

Ben de denedim git fetch modbir getirme yapmak göründüğü, (ama olamaz muhtemelen, bir şifre sorulmaz değil çünkü!), Ancak git logve git showyeni kaydedilmesini varlığını inkar. Şimdiye kadar rmmodülü yeni çalıştırıyorum ve yeniden ekliyorum, ancak bu prensipte yanlış ve pratikte sıkıcı.


5
David Z'nin cevabı bunu yapmanın daha iyi bir yolu gibi görünüyor - artık Git --remoteseçeneği ile ihtiyacınız olan işlevselliğe sahip olduğuna göre , belki de bunu Jason'ın cevabındaki "elle" yaklaşımı yerine kabul edilen cevap olarak işaretlemek yararlı olacaktır?
Mark Amery

1
@MarkAmery ile son derece katılıyorum. Jason çalışan bir çözüm sunarken, bunu yapmak amaçlanan yol değildir, çünkü alt modülün tamamlama işaretçisini yanlış yürütme tanımlayıcısında bırakır. Yeni --remote, bu noktada kesinlikle daha iyi bir çözümdür ve bu soru bir Github Gist'ten alt modüller hakkında bağlantılı olduğundan, gelen okuyucuların yeni cevabı görmesinin daha iyi olacağını düşünüyorum.
MutantOctopus

hunter2Şifre ile hoş bir dokunuş : o)
lfarroco

Yanıtlar:


1458

git submodule updateKomut aslında zaten superproject endeksi belirtilen kesinleştirme dışarı her çek için submodules istediğiniz Git söyler. İsterseniz güncelleştirmek son için alt modül kendi uzaktan edinilebilir işlemek, sen Altmodüllerin doğrudan bunu yapmak gerekecektir.

Özet olarak:

# Get the submodule initially
git submodule add ssh://bla submodule_dir
git submodule init

# Time passes, submodule upstream is updated
# and you now want to update

# Change to the submodule directory
cd submodule_dir

# Checkout desired branch
git checkout master

# Update
git pull

# Get back to your project root
cd ..

# Now the submodules are in the state you want, so
git commit -am "Pulled down update to submodule_dir"

Veya meşgul biriyseniz:

git submodule foreach git pull origin master

335
git submodule foreach git pull
Mathias Bynens

87
@Nicklas Bu durumda kullanın git submodule foreach git pull origin master.
Mathias Bynens

54
Bu noktada, tüm bu düzeltmelerle birlikte, açıklayıcı bir blog yazısı yazacak ve beni orada işaret edecek birine ihtiyacım var. Lütfen.
Suz

25
'foreach' yaklaşımında ufak bir iyileştirme - alt modüllerde alt modüllerin olması durumunda - tekrarlayıcı eklemek isteyebilirsiniz. böylece: git submodule foreach --recursive git pull origin master.
orion elenzil

4
@Abdull -aiçin anahtarı git commit"modifiye ve silinmiş otomatik sahne dosyalarına komutu [s] söyle, ancak Git söylemedim yeni dosyalar hakkında etkilenmez vardır."
godfrzero

473

Git 1.8.2 --remote, tam olarak bu davranışı etkinleştirecek yeni bir seçeneğe sahiptir . Koşu

git submodule update --remote --merge

her alt modülün akış yönünde en son değişiklikleri alır, birleştirir ve alt modülün en son revizyonunu kontrol eder. Gibi belgeler koyar o:

--Remote

Bu seçenek yalnızca güncelleme komutu için geçerlidir. Alt modülü güncellemek için süper projenin kayıtlı SHA-1'ini kullanmak yerine, alt modülün uzaktan izleme kolunun durumunu kullanın.

Bu, git pullher alt modülde çalışmaya eşdeğerdir , bu genellikle tam olarak istediğiniz şeydir.


4
" git pullher alt modülde çalışmaya eşdeğerdir" Açıklığa kavuşturmak için, cevabınız ile git submodule foreach git pull? arasında hiçbir fark yoktur (kullanıcının bakış açısından).
Dennis

3
@Dennis aslında aynı şeyi yapıyor, ancak işlevselliğin tamamen aynı olup olmadığından emin değilim . Bilmediğim bazı küçük farklılıklar olabilir, örneğin iki komutun bazı yapılandırma ayarlarına yanıt verme şekli.
David Z

5
Keşke bu 10,000X'i yükseltebilseydim. Bu neden git'in belgelerinde hiçbir yerde gösterilmiyor? Büyük gözetim.
serraosays

4
Benim için aslında oldukça farklıydılar; foreach git pullsadece onları kontrol ettiler, ancak ana deponun işaretçisini alt modülün daha yeni taahhüdüne işaret edecek şekilde güncellemediler. Sadece --remoteonunla son taahhüdü işaret etti.
Ela782

5
neden --merge seçeneği? Ne fark eder ki?
mFeinstein

127

Proje üst dizininizde şunu çalıştırın:

git submodule update --init

Veya tekrarlayan alt modülleriniz varsa:

git submodule update --init --recursive

Bazen bu hala işe yaramaz, çünkü bir şekilde alt modül güncellenirken yerel alt modül dizininde yerel değişiklikleriniz vardır.

Çoğu zaman, yerel değişiklik yapmak istediğiniz değişiklik olmayabilir. Bu, alt modülünüzdeki vb. Bir dosya silme nedeniyle olabilir. Öyleyse, yerel alt modül dizininizde ve proje üst dizininizde bir sıfırlama yapın, tekrar çalıştırın:

git submodule update --init --recursive

5
gerçek cevap budur. bir şekilde uzak depoma itebilir miyim?
MonsterMMORPG

Bu yeni alt modüller için işe yarıyor! Diğerlerini güncelleyebildim ama yeni alt modüllerin klasörü bu komutu çalışana kadar boş kalacaktı.
Alexis Wilke

1
Mevcut alt modüller için değişiklik yapmaz
Sergey G.

73

Ana projeniz, alt modülün olması gereken belirli bir taahhüde işaret ediyor. git submodule updatebaşlatılan her alt modülde bu taahhüdü kontrol etmeye çalışır. Alt modül gerçekten bağımsız bir havuzdur - sadece alt modülde yeni bir taahhüt yaratır ve bunu itmek yeterli değildir. Ayrıca ana projeye alt modülün yeni sürümünü açıkça eklemeniz gerekir.

Yani, sizin durumunuzda, alt modülde doğru taahhüdü bulmalısınız - varsayalım master:

cd mod
git checkout master
git pull origin master

Şimdi ana projeye geri dönün, alt modülü hazırlayın ve bunu taahhüt edin:

cd ..
git add mod
git commit -m "Updating the submodule 'mod' to the latest version"

Şimdi ana projenin yeni versiyonunu itin:

git push origin master

Bu noktadan sonra, başka biri ana projesini git submodule updategüncellerse, onlar için alt modülün başlatıldığı varsayılarak güncellenir.


24

Bu tartışmada iki farklı senaryo karıştırılıyor gibi görünüyor:

Senaryo 1

Ana veri havuzumun alt modüllere işaret eden işaretlerini kullanarak, her alt modülde üst veri havuzunun işaret ettiği taahhüdü kontrol etmek istiyorum, muhtemelen ilk önce tüm alt modüllerden yineleme yaptıktan ve bunları uzaktan güncelleme / çekme işleminden sonra.

Bu, belirtildiği gibi,

git submodule foreach git pull origin BRANCH
git submodule update

OP'nin amaçladığı şey olduğunu düşünüyorum Senaryo 2

Bir veya daha fazla alt modülde yeni şeyler oldu ve 1) bu değişiklikleri çekmek ve 2) ana depoyu bu / bu alt modüllerin HEAD (en son) taahhüdüne işaret edecek şekilde güncellemek istiyorum.

Bu,

git submodule foreach git pull origin BRANCH
git add module_1_name
git add module_2_name
......
git add module_n_name
git push origin BRANCH

Çok pratik değil, çünkü üst havuzun taahhüt işaretlerini güncellemek için örneğin bir komut dosyasındaki tüm n alt modüllerine n yollarını sabitlemek zorunda kalacaksınız.

Ana modül işaretçisini (kullanarak git add) alt modülün başına işaret edecek şekilde güncelleyerek, her alt modül boyunca otomatik bir yinelemeye sahip olmak güzel olurdu .

Bunun için bu küçük Bash senaryosunu yaptım:

git-update-submodules.sh

#!/bin/bash

APP_PATH=$1
shift

if [ -z $APP_PATH ]; then
  echo "Missing 1st argument: should be path to folder of a git repo";
  exit 1;
fi

BRANCH=$1
shift

if [ -z $BRANCH ]; then
  echo "Missing 2nd argument (branch name)";
  exit 1;
fi

echo "Working in: $APP_PATH"
cd $APP_PATH

git checkout $BRANCH && git pull --ff origin $BRANCH

git submodule sync
git submodule init
git submodule update
git submodule foreach "(git checkout $BRANCH && git pull --ff origin $BRANCH && git push origin $BRANCH) || true"

for i in $(git submodule foreach --quiet 'echo $path')
do
  echo "Adding $i to root repo"
  git add "$i"
done

git commit -m "Updated $BRANCH branch of deployment repo to point to latest head of submodules"
git push origin $BRANCH

Çalıştırmak için,

git-update-submodules.sh /path/to/base/repo BRANCH_NAME

ayrıntı

Her şeyden önce, $ BRANCH (ikinci argüman) adlı şubenin tüm depolarda bulunduğunu varsayıyorum. Bunu daha da karmaşık hale getirmek için çekinmeyin.

İlk birkaç bölüm, argümanların orada olup olmadığını kontrol etmektir. Sonra üst veri havuzunun en son şeylerini çekiyorum (sadece çekiş yaptığımda --ff (hızlı yönlendirme) kullanmayı tercih ediyorum. Rebase off, BTW).

git checkout $BRANCH && git pull --ff origin $BRANCH

Daha sonra, yeni alt modüller eklenmişse veya henüz başlatılmamışsa bazı alt modüllerin başlatılması gerekebilir:

git submodule sync
git submodule init
git submodule update

Sonra tüm alt modülleri güncellerim / çekerim:

git submodule foreach "(git checkout $BRANCH && git pull --ff origin $BRANCH && git push origin $BRANCH) || true"

Birkaç şey dikkat edin: Her şeyden önce, bazı Git komutlarını kullanarak zincirleme yapıyorum &&- yani önceki komut hatasız yürütülmelidir.

Olası başarılı bir çekimden sonra (uzaktan kumandada yeni şeyler bulunursa), istemcide olası bir birleştirme işleminin geride kalmamasını sağlamak için bir itme yaparım. Yine, sadece olur eğer bir çekme aslında yeni şeyler getirdi.

Son olarak, son || truekomut dosyasının hatalar üzerinde devam etmesini sağlamaktır. Bunu yapmak için, yinelemedeki her şey çift tırnak içine alınmalı ve Git komutları parantez içine alınmalıdır (operatör önceliği).

En sevdiğim kısım:

for i in $(git submodule foreach --quiet 'echo $path')
do
  echo "Adding $i to root repo"
  git add "$i"
done

--quiet'MODULE_PATH Girme' çıkışını kaldıran tüm alt modülleri yineleyin. Kullanılması 'echo $path'(tek tırnak içinde olmalıdır), alt modülün yolu çıkışına yazılı alır.

Bu göreli alt modül yolları listesi bir dizide ( $(...)) yakalanır - son olarak bunu yineleyin ve git add $iüst veri havuzunu güncellemek için yapın.

Son olarak, üst havuzun güncellendiğini açıklayan bazı mesajlar içeren bir taahhüt. Hiçbir şey yapılmadıysa, bu işlem varsayılan olarak yok sayılır. Bunu başlangıç ​​noktasına itin ve işiniz bitti.

Daha sonra bir zamanlanmış otomatik dağıtım zincirleri bir Jenkins işinde çalışan bir komut dosyası var ve bir cazibe gibi çalışır.

Umarım bu birisine yardımcı olur.


2
! @ # $% SO Sizinkine benzer komut dosyaları kullanıyoruz; bir not: `` git submodule foreach --quiet 'echo $ path' 'yerine `` for döngülerinin içinde `` git submodule foreach - recursive --quiet pwd' 'kullanıyoruz. pwdKomut her alt birimin mevcut için uygun 'mutlak yol' yazdırır; büyük bir projede bulunabilecek alt modüllerin içindeki altmodüller -... dahil olmak üzere tüm altmodülleri --recursiveziyaret etmemizi sağlar . Dizinleri ile bela oldu Her iki yöntem örneğin boşluk içerir dolayısıyla politika etmektir asla boşluk yerde projelerimizde kullanıyoruz. /c/Users/Ger/Project\ Files/...
Ger Hobbelt

2
Bu güzel ve sorunun ne olduğu hakkında bazı cevaplarda bir yanlış anlama olduğu doğru, ancak David Z'in mükemmel cevabının işaret ettiği gibi, komut dosyanız gereksizdir, çünkü fonksiyonellik 2013 ortasından beri Git'e inşa edilmiştir. --remoteseçeneği eklediler . git submodule update --remotesenaryonuzun yaptığı gibi davranır.
Mark Amery

@GerHobbelt Teşekkürler. Haklısın, sadece 1 seviye alt modülümüz var, bu yüzden onu tekrarlayan yapmayı asla düşünmedim. Beklendiği gibi çalıştığını doğrulama şansım olmadan önce betiği güncellemeyeceğim, ancak kesinlikle betiğim alt alt modülleri içeriyor. Klasörlerdeki boşluklara gelince, bu kesinlikle kaçınılması gereken bir şey gibi geliyor! : S
Frederik Struck-Schøning

@MarkAmery Geri bildiriminiz için teşekkür ederiz. Ancak 1 sorun görüyorum: alt argümanlar için alt-modül için şube belirtebilme by-argument Git kılavuzundan: The remote branch used defaults to master, but the branch name may be overridden by setting the submodule.<name>.branch option in either .gitmodules or .git/config (with .git/config taking precedence).Bunu master'dan başka bir şubeye her yapmak istediğimde .gitmodules veya .git / config düzenlemek istemiyorum. Ama belki bir şey kaçırmışımdır? Ayrıca, yöntem özyinelemeli birleştirmeleri zorunlu kılıyor gibi görünmektedir (bu nedenle hızlı ileri alma olasılığını kaçırmaktadır).
Frederik Struck-Schøning

Son şey: @ DavidZ'in yöntemini denedim ve kesin olanı yapmıyorum, yapmaya karar verdim (ve hangi op hakkında soruyordum): Ebeveyne alt modüllerin HEAD taahhüdünü ekleme (yani "işaretçiyi güncelleme") ). Bununla birlikte, tüm alt modüllerde son değişiklikleri almak ve birleştirmek için tek işi çok iyi (ve daha hızlı) yapıyor gibi görünüyor. Ne yazık ki, varsayılan olarak yalnızca ana daldan (.gitmodules dosyasını düzenlemezseniz (yukarıya bakın)).
Frederik Struck-Schøning

19

Alt modülleri getirmek için sade ve basit:

git submodule update --init --recursive

Şimdi bunları en son ana şubeye güncellemeye devam edin (örneğin):

git submodule foreach git pull origin master

12

Unutmayın, modern güncelleme alt modülü taahhütleri şöyle olur:

git submodule update --recursive --remote --merge --force

Eski form:

git submodule foreach --quiet git pull --quiet origin

Dışında ... bu ikinci form gerçekten "sessiz" değil.

Bakınız Nguy an Thái Ngọc Duy ( pclouds) tarafından a282f5a (12 Nis 2019 ) .
(Göre Birleştirilmiş Junio Cı Hamano - gitster- içinde işlemek f1c9f6c , 25 Nisan 2019)

submodule foreach: " <command> --quiet" sorununa saygı gösterilmiyor

Robin bunu bildirdi

git submodule foreach --quiet git pull --quiet origin

artık gerçekten sessiz değil. Fc1b924'ten ( : port subcommand ' ', kabuktan C'ye, 2018-05-10, Git v2.19.0-rc0'dan)
önce sessiz olmalı, çünkü seçenekleri yanlışlıkla yiyemezsiniz.submodulesubmoduleforeachparseopt

" git pull" --quiet, verilmemiş gibi davranır .

Bunun nedeni parseoptde submodule--helperhem ayrıştırmak için çalışacağız --quietonlar ForEach en seçenekleri, değilse gibi seçenekleri git-pull'ın.
Ayrıştırılan seçenekler komut satırından kaldırılır. Böylece daha sonra çektiğimizde,

git pull origin

Alt modül yardımcısını çağırırken, " --" önüne " " eklemek, gerçekten ait olmayan seçenekleri ayrıştırmak için git pullduracaktır .parseoptsubmodule--helper foreach

PARSE_OPT_KEEP_UNKNOWNbir güvenlik önlemi olarak çıkarılır. parseoptbilinmeyen seçenekleri asla görmemeli veya bir şeyler ters gitti. Ben de onlara bakarken bir çift kullanım dize güncelleme vardır.

Ona da, ben de "add --" geçmesi diğer alt komutlar için " $@için" submodule--helper. " $@" bu durumlarda yollar vardır ve olma olasılığı daha azdır --something-like-this.
Ama nokta hala duruyor, git-submoduleseçenekler neler, yollar neler ayrıştırılmış ve sınıflandırılmıştır.
submodule--helpergeçtikleri yolları hiç git-submodulede benzemeseler bile seçenek olarak düşünmemelidirler .


Git 2.23 (3.Çeyrek 2019) başka bir sorunu düzeltiyor: " git submodule foreach", her alt modülde çalıştırılacak komuta iletilen komut satırı seçeneklerini " --recursive" seçeneği kullanımdayken doğru şekilde korumadı .

Bkz. Morian Sonnet ( momoson) tarafından 30db18b (24 Haz 2019) taahhüdü .
(Göre Birleştirilmiş Junio Cı Hamano - gitster- içinde işlemek 968eecb , 9 Temmuz 2019)

submodule foreach: seçeneklerin yinelemesini düzeltin

Arayan:

git submodule foreach --recursive <subcommand> --<option>

seçeneğin --<option>bilinmediğini belirten bir hataya neden olur submodule--helper.
Tabii ki, sadece <option>geçerli bir seçenek olmadığında git submodule foreach.

Bunun nedeni, yukarıdaki çağrının dahili olarak bir alt modül çağrısına çevrilmesidir - yardımcı:

git submodule--helper foreach --recursive \
    -- <subcommand> --<option>

Bu çağrı, birinci seviye alt modül içindeki seçeneği ile alt komutun yürütülmesi ile başlar ve submodule foreachçağrının bir sonraki yinelemesini çağırarak devam eder.

git --super-prefix <submodulepath> submodule--helper \
   foreach --recursive <subcommand> --<option>

birinci seviye alt modülün içinde. Alt komutun önündeki çift tirenin eksik olduğunu unutmayın.

Bu sorun yalnızca son zamanlarda ortaya çıkmaya başlıyor, çünkü a282f5a komutundaPARSE_OPT_KEEP_UNKNOWN argüman ayrıştırma bayrağı git submodule foreachkaldırıldı . Bu nedenle, bilinmeyen seçenek şu anda şikayet ediliyor, çünkü argüman ayrıştırma çift tire ile düzgün bir şekilde sonlandırılmıyor.

Bu işlem, özyineleme sırasında alt komutun önüne çift tire ekleyerek sorunu giderir.


7
git pull --recurse-submodules

Bu, en son taahhütleri çekecektir.


4

Benim durumumda istedim git en son sürüme güncellemek ve aynı zamanda eksik dosyaları yeniden doldurmak .

Aşağıdakiler eksik dosyaları geri yükledi (sayesinde --forceburada belirtilmemiş gibi görünüyor), ancak yeni taahhütler almadı:

git submodule update --init --recursive --force

Bu yaptı:

git submodule update --recursive --remote --merge --force


3

@ Jason bir şekilde doğrudur ama tamamen değil.

Güncelleme

Kayıtlı alt modülleri güncelleyin, yani eksik alt modülleri klonlayın ve içeren deponun dizininde belirtilen taahhüdü kontrol edin. Bu, --rebase veya --merge belirtilmemişse veya anahtar submodule değilse $ HEAD alt modüllerinin sökülmesini sağlar.

Yani, git submodule updateödeme yapar, ancak içeren deponun dizinindeki taahhüttür. Henüz yeni giriş akışını henüz bilmiyor. Bu nedenle alt modülünüze gidin, istediğiniz taahhüdü alın ve güncellenmiş alt modül durumunu ana depoda taahhüt edin ve ardından git submodule update.


1
Alt modülü farklı bir işleme git submodule updatetaşıyıp sonra çalıştırırsam güncelleme, alt modülü süper projenin geçerli HEAD'ında belirtilen işleme taşıyacaktır. (üst projedeki en son taahhüt ne olursa olsun, alt projenin olması gerektiğini söylüyor - bu davranış, Jason'ın gönderisindeki açıklamadan sonra bana mantıklı geliyor) Ayrıca getiriliyor gibi görünüyor, ancak sadece alt projenin yanlış taahhütte olması durumunda Bu da benim karışıklığımı arttırıyordu.
Thanatos

2

İşte her şeyi ustada en son sürüme güncellemek için harika bir astar:

git submodule foreach 'git fetch origin --tags; git checkout master; git pull' && git pull && git submodule update --init --recursive

Mark Jaquith'e teşekkürler


2

Ana bilgisayar dalını bilmiyorsanız, şunları yapın:

git submodule foreach git pull origin $(git rev-parse --abbrev-ref HEAD)

Ana Git deposunun bir dalını alacak ve her alt modül için aynı dalın bir çekmesini yapacak.


0

masterHer alt modül için ödeme dalını arıyorsanız - bu amaçla aşağıdaki komutu kullanabilirsiniz:

git submodule foreach git checkout master
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.