Zaktualizuj Git submodule do najnowszego commita na origin

Mam projekt z podmodułem Git. Jest z ssh://... URL, i jest na commit A. Commit B został wypchnięty na ten adres URL i chcę, aby podmoduł odzyskał commit i zmienił na niego.

Rozumiem, że git submodule update powinno to zrobić, ale tak nie jest. nic nie robi (brak wyjścia, kod wyjścia sukcesu). Oto przykład:

$ 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
$ ...

Próbowałem również git fetch mod, który wydaje się robić aport (ale nie może, bo to nie monituje o hasło!), ale git log i git show zaprzeczają istnieniu nowych commitów. Do tej pory po prostu[5]}-ing moduł i ponowne dodanie go, ale jest to zarówno złe w zasadzie i żmudne w praktyce.

Author: Cœur, 2011-04-29

9 answers

The git submodule update polecenie mówi Gitowi, że chcesz, aby każdy z Twoich podmodułów sprawdzał commit już określony w indeksie superprojekt. Jeśli chcesz zaktualizować swoje podmoduły do najnowszego commita dostępnego z ich pilota, musisz to zrobić bezpośrednio w podmodułach.

Tak w podsumowaniu:

# 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"

Lub, jeśli jesteś zajętą osobą:

git submodule foreach git pull origin master
 1103
Author: Jason,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-01 18:36:57

Git 1.8.2 zawiera nową opcję --remote, która umożliwi dokładnie takie zachowanie. Running

git submodule update --remote --merge

Pobierze najnowsze zmiany z podmodułu, połączy je i sprawdzi najnowszą wersję podmodułu. Jak to ujął docs :

--remote

Ta opcja jest ważna tylko dla polecenia update. Zamiast używać nagranego SHA-1 superprojektu do aktualizacji podmodułu, użyj statusu zdalnego śledzenia podmodułu branch.

Jest to równoznaczne z uruchomieniem git pull w każdym podmodule, co generalnie jest dokładnie tym, czego chcesz.

 324
Author: David Z,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-01 18:36:05

W katalogu nadrzędnym projektu Uruchom:

git submodule update --init 

Lub jeśli masz rekurencyjne podmoduły Uruchom:

git submodule update --init --recursive

Czasami to nadal nie działa, ponieważ w jakiś sposób masz lokalne zmiany w lokalnym katalogu submodule, podczas gdy submodule jest aktualizowany.

Przez większość czasu lokalna zmiana może nie być tą, którą chcesz wprowadzić. Może się to zdarzyć z powodu usunięcia pliku w podmodule itp. Jeśli tak, wykonaj reset w lokalnym katalogu podmoduł i w rodzicu projektu katalog uruchom ponownie:

git submodule update --init --recursive 
 96
Author: pinux,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-18 08:25:40

Twój główny projekt wskazuje na konkretny commit, w którym powinien znajdować się podmoduł. git submodule update robi to, aby sprawdzić ten commit w każdym podmodule, który został zainicjowany. Submodule jest tak naprawdę niezależnym repozytorium - samo stworzenie nowego commita w submodule i wciskanie tego nie wystarczy, musisz również wyraźnie dodać nową wersję submodule w głównym projekcie.

Więc w Twoim przypadku powinieneś znaleźć odpowiedni commit w podmodule-Załóżmy, że "końcówka mistrza": {]}

cd mod
git checkout master
git pull origin master

Teraz wróć do głównego projektu, ustaw podmoduł i zatwierdź:

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

Teraz wypchnij nową wersję głównego projektu:

git push origin master

Od tego momentu, Jeśli ktoś inny zaktualizuje swój główny projekt, to git submodule update dla niego zaktualizuje podmoduł, zakładając, że został zainicjowany.

 65
Author: Mark Longair,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-29 06:12:17

Wygląda na to, że w tej dyskusji mieszają się dwa różne scenariusze:

Scenariusz 1

Używając wskaźników mojego rodzica repo do podmodułów, chcę sprawdzić commit w każdym podmodule, na który wskazuje rodzic repo, prawdopodobnie po pierwszej iteracji przez wszystkie podmoduły i aktualizacji / ściągnięciu ich z pilota.

Jest to, jak zaznaczono, zrobione

git submodule foreach git pull origin BRANCH
git submodule update

Scenariusz 2, który moim zdaniem jest celem OP at

Nowe rzeczy wydarzyły się w 1 lub więcej podmodułach i chcę 1) wyciągnąć te zmiany i 2) zaktualizować repo rodzica, aby wskazać HEAD (latest) commit tego/tych podmodułów.

To będzie zrobione przez

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

Nie jest to zbyt praktyczne, ponieważ trzeba by kodować na twardo n ścieżek do wszystkich N podmoduł, np. w skrypcie, aby zaktualizować wskaźniki zatwierdzania repo.

Co byłoby fajne dla automatycznej iteracji za pośrednictwem każdego podmodułu, aktualizowanie nadrzędny wskaźnik repo (używając git add) wskazuje na główkę podmodułu (- ów).

W tym celu zrobiłem mały skrypt bash:

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

Aby go uruchomić, wykonaj

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

Opracowanie

Po pierwsze, zakładam, że gałąź o nazwie $BRANCH (2nd argument) istnieje na wszystkich repo.

Pierwsza para odcinków to jakieś sprawdzenie, czy są argumenty. Następnie wyciągam najnowsze rzeczy repo rodzica (wolę użyć --ff (fast-forwarding), gdy tylko robię ściągi. Mam rebase off, btw).

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

Wtedy może być konieczna inicjalizacja podmoduł, jeśli nowe podmoduły zostały dodane lub nie są jeszcze inicjalizowane:

git submodule sync
git submodule init
git submodule update

Następnie aktualizuję / ściągam wszystkie podmoduły:

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

Zwróć uwagę na kilka rzeczy: po pierwsze, łączę kilka komend git za pomocą && - co oznacza, że poprzednie polecenie musi być wykonane bez błąd.

Po ewentualnym pomyślnym ściągnięciu (jeśli nowe rzeczy zostały znalezione na pilocie), wykonuję push, aby upewnić się, że ewentualne merge-commit nie zostanie pozostawione na kliencie. Znowu, zdarza się tylko jeśli przyciąganie rzeczywiście przyniosło nowe rzeczy.

Ostatecznie, || true jest zapewnienie, że skrypt nadal na błędy. Aby to zadziałało, wszystko w iteracji musi być zawinięte w podwójne cudzysłowy, a polecenia git-owinięte w parantezy (operator pierwszeństwo).

Moja ulubiona część:

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

Iteracja wszystkich podmoduł-za pomocą --quiet, która usuwa wyjście 'Wprowadzanie MODULE_PATH'. Używając 'echo $path' (musi być w cudzysłowach), ścieżka do podmodułu zostanie zapisana do wyjścia.

Ta lista względnych ścieżek podrzędnych jest przechwytywana w tablicy ($(...)) - na koniec iteratuj to i wykonaj git add $i, aby zaktualizować repo nadrzędne.

Na koniec commit z jakimś Komunikatem wyjaśniającym, że repo rodzica zostało zaktualizowane. Ten commit będzie domyślnie ignorowany, jeśli nic nie zostało zrobione. Popchnij to do źródła i gotowe.

Mam skrypt uruchamiający to w jenkins-job, który łączy się z zaplanowanym automatycznym wdrożeniem i działa jak urok.

Mam nadzieję, że to komuś pomoże.
 17
Author: Frederik Struck-Schøning,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-15 09:24:42

Proste i proste, aby pobrać podmoduły:

git submodule update --init --recursive

A teraz kontynuuj aktualizację ich do najnowszej gałęzi master (na przykład):

git submodule foreach git pull origin master
 12
Author: Mincă Daniel Andrei,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-17 20:48:04

@Jason ma rację w pewnym sensie, ale nie do końca.

Update

Zaktualizuj zarejestrowane moduły podrzędne, tj. klonowanie brakujących podmodułów i sprawdź commit określony w indeks repozytorium zawierającego. Dzięki temu Głowica podmodułowa będzie odłączony, chyba że --rebase lub --merge jest określony lub klucz submodule.$name.update jest ustawiony na rebase lub merge.

Więc, git submodule update robi checkout, ale rzecz w tym, że jest to commit w indeks repozytorium zawierającego. Nie wie jeszcze o nowym commicie w ogóle. Więc idź do swojego podmodułu, Pobierz commit, który chcesz i zatwierdź zaktualizowany stan podmodułu w głównym repo, a następnie wykonaj git submodule update

 4
Author: manojlds,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-29 06:18:00

Oto niesamowita jedna linijka, która zaktualizuje wszystko do najnowszej wersji master:

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

Dzięki Markowi Jaquith

 0
Author: dustinrwh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-28 04:29:02

W moim przypadku chciałem zaktualizować git do najnowszej i jednocześnie uzupełnić brakujące pliki.

Poniższy plik przywrócił brakujące pliki (dzięki --force, o którym tu nie wspomniano), ale nie ściągnął żadnych nowych commitów:

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

To:

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

 0
Author: noseratio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-26 05:24:53