Parece que dois cenários diferentes estão sendo misturados nesta discussão:
Cenário 1
Usando os ponteiros do meu repositório pai para submódulos, quero verificar o commit em cada submódulo para o qual o repositório pai está apontando, possivelmente depois de primeiro percorrer todos os submódulos e atualizá-los / removê-los do controle remoto.
Isso é, como apontado, feito com
git submodule foreach git pull origin BRANCH
git submodule update
Cenário 2, que eu acho que é o objetivo do OP
Novas coisas aconteceram em um ou mais submódulos, e eu quero 1) extrair essas alterações e 2) atualizar o repositório pai para apontar para o commit HEAD (mais recente) deste / desses submódulos.
Isso seria feito por
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
Não é muito prático, pois você teria que codificar n caminhos para todos os n submódulos em um script para atualizar os ponteiros de confirmação do repositório pai.
Seria legal ter uma iteração automatizada em cada submódulo, atualizando o ponteiro do repositório pai (usando git add
) para apontar para a cabeça do submódulo (s).
Para isso, criei este pequeno script 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
Para executá-lo, execute
git-update-submodules.sh /path/to/base/repo BRANCH_NAME
Elaboração
Primeiro, suponho que o ramo com o nome $ BRANCH (segundo argumento) exista em todos os repositórios. Sinta-se livre para tornar isso ainda mais complexo.
O primeiro par de seções é uma verificação de que os argumentos estão lá. Então eu puxo as coisas mais recentes do repositório pai (eu prefiro usar --ff (avanço rápido) sempre que estou fazendo pulls. Eu me refiz, BTW).
git checkout $BRANCH && git pull --ff origin $BRANCH
Em seguida, pode ser necessário inicializar algum sub-módulo, se novos submódulos foram adicionados ou ainda não foram inicializados:
git submodule sync
git submodule init
git submodule update
Então eu atualizo / puxo todos os submódulos:
git submodule foreach "(git checkout $BRANCH && git pull --ff origin $BRANCH && git push origin $BRANCH) || true"
Observe algumas coisas: Primeiro, estou encadeando alguns comandos Git usando &&
- o que significa que o comando anterior deve ser executado sem erros.
Após uma possível solicitação bem-sucedida (se novas coisas foram encontradas no controle remoto), faço um esforço para garantir que uma possível confirmação de mesclagem não seja deixada para trás no cliente. Novamente, isso só acontece se uma atração realmente trouxer coisas novas.
Finalmente, a final || true
é garantir que o script continue com erros. Para fazer isso funcionar, tudo na iteração deve estar entre aspas duplas e os comandos Git entre parênteses (precedência do operador).
A minha parte favorita:
for i in $(git submodule foreach --quiet 'echo $path')
do
echo "Adding $i to root repo"
git add "$i"
done
Itere todos os submódulos - com --quiet
, o que remove a saída 'Entering MODULE_PATH'. Usando 'echo $path'
(deve estar entre aspas simples), o caminho para o submódulo é gravado na saída.
Essa lista de caminhos relativos ao submódulo é capturada em uma matriz ( $(...)
) - finalmente itere e faça git add $i
para atualizar o repositório pai.
Finalmente, uma confirmação com alguma mensagem explicando que o repositório pai foi atualizado. Esse commit será ignorado por padrão, se nada for feito. Empurre isso para a origem e pronto.
Eu tenho um script executando isso em um trabalho de Jenkins que se liga a uma implantação automatizada agendada posteriormente e funciona como um encanto.
Espero que isso ajude alguém.
--remote
opção, talvez seja útil marcar isso como a resposta aceita e não a abordagem "manual" na resposta de Jason?