Un modo semplice per estrarre i sottomoduli Git più recenti
-
06-07-2019 - |
Domanda
Stiamo usando i sottomoduli git per gestire un paio di grandi progetti che hanno dipendenze da molte altre librerie che abbiamo sviluppato. Ogni libreria è un repository separato portato nel progetto dipendente come sottomodulo. Durante lo sviluppo, spesso vogliamo semplicemente prendere l'ultima versione di ogni sottomodulo dipendente.
Git ha un comando integrato per farlo? In caso contrario, che ne dici di un file batch di Windows o simile che può farlo?
Soluzione
Se è la prima volta fai il checkout di un repository, devi prima usare --init
:
git submodule update --init --recursive
Per git 1.8.2 o superiore è stata aggiunta l'opzione --remote
per supportare l'aggiornamento agli ultimi suggerimenti delle filiali remote:
git submodule update --recursive --remote
Questo ha l'ulteriore vantaggio di rispettare qualsiasi " non default " i rami specificati nei file .gitmodules
o .git / config
(se ne hai uno, il default è origin / master, nel qual caso alcune delle altre risposte qui sarebbero funziona anche).
Per git 1.7.3 o versioni successive puoi usare (ma i trucchi qui sotto su quale aggiornamento si applica ancora):
git submodule update --recursive
o
git pull --recurse-submodules
se si desidera eseguire il pull dei sottomoduli agli ultimi commit, al di là di ciò a cui punta il repository.
Vedi git-submodule (1) per dettagli
Altri suggerimenti
Se è necessario inserire elementi per i sottomoduli nei repository dei sottomoduli, utilizzare
git pull --recurse-submodules
una funzionalità git appresa per la prima volta in 1.7.3.
Ma questo non verificherà i commit (quelli indicati dal repository principale) nei sottomoduli
Per verificare gli commit corretti nei sottomoduli, è necessario aggiornarli dopo averlo tirato usando
git submodule update --recursive --remote
Su init esegue il seguente comando:
git submodule update --init --recursive
dall'interno della directory git repo, funziona meglio per me.
Verranno estratti tutti gli ultimi inclusi i sottomoduli.
Explained
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.
Dopodiché puoi semplicemente eseguire:
git submodule update --recursive
dall'interno della directory git repo, funziona meglio per me.
Verranno estratti tutti gli ultimi inclusi i sottomoduli.
Nota: è del 2009 e potrebbe essere stato buono allora, ma ora ci sono opzioni migliori.
Lo usiamo. Si chiama 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
Basta inserirlo in una directory bin adatta (/ usr / local / bin). Se su Windows, potrebbe essere necessario modificare la sintassi per farlo funzionare :)
Aggiornamento:
In risposta al commento dell'autore originale su come inserire tutti i HEAD di tutti i sottomoduli - questa è una buona domanda.
Sono abbastanza sicuro che git
non abbia un comando per questo internamente. Per fare ciò, dovresti identificare cosa è realmente HEAD per un sottomodulo. Potrebbe essere semplice come dire master
è il ramo più aggiornato, ecc ...
In seguito, crea un semplice script che procede come segue:
- controlla
git submodule status
per " modificato " repository. Il primo carattere delle righe di output indica questo. Se un sub-repo viene modificato, potresti NON voler procedere. - per ogni repo elencato, cd nella sua directory ed esegui
git checkout master & amp; & amp; git pull
. Controlla errori. - Alla fine, ti suggerisco di stampare un display all'utente per indicare lo stato corrente dei sottomoduli - forse spingerli ad aggiungere tutto e impegnarsi?
Vorrei menzionare che questo stile non è proprio quello per cui sono stati progettati i sottomoduli git. In genere, vuoi dire " LibraryX " è nella versione "2,32"; e rimarrà tale fino a quando non lo dirò a " upgrade " ;.
Questo è, in un certo senso, quello che stai facendo con lo script descritto, ma solo più automaticamente. È necessaria la cura!
Aggiornamento 2:
Se sei su una piattaforma Windows, potresti voler usare Python per implementare lo script in quanto è molto capace in queste aree. Se sei su unix / linux, allora suggerisco solo uno script bash.
Hai bisogno di chiarimenti? Pubblica un commento.
Henrik è sulla buona strada. Il comando 'foreach' può eseguire qualsiasi script shell arbitrario. Due opzioni per estrarre l'ultima potrebbe essere,
git submodule foreach git pull origin master
e
git submodule foreach /path/to/some/cool/script.sh
Questo eseguirà l'iterazione attraverso tutti i sottomoduli inizializzati ed eseguirà i comandi dati.
Quanto segue ha funzionato per me su Windows.
git submodule init
git submodule update
Modifica :
Nei commenti è stato sottolineato (da philfreo ) che è richiesta l'ultima versione. Se sono presenti sottomoduli nidificati che devono trovarsi nella loro ultima versione:
git submodule foreach --recursive git pull
----- Commento obsoleto di seguito -----
Non è questo il modo ufficiale per farlo?
git submodule update --init
Lo uso ogni volta. Nessun problema finora.
Modifica
Ho appena scoperto che puoi usare:
git submodule foreach --recursive git submodule update --init
Che tirerà anche in modo ricorsivo tutti i sottomoduli, cioè le dipendenze.
Come può succedere che il ramo predefinito dei tuoi sottomoduli sia non master
, è così che automatizzo gli aggiornamenti completi dei sottomoduli Git:
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'
Prima volta
Clone and Init Submodule
git clone git@github.com:speedovation/kiwi-resources.git resources
git submodule init
Resto
Durante lo sviluppo basta estrarre e aggiornare il sottomodulo
git pull --recurse-submodules && git submodule update --recursive
Aggiorna il sottomodulo Git all'ultimo commit sull'origine
git submodule foreach git pull origin master
Il modo preferito dovrebbe essere inferiore
git submodule update --remote --merge
nota: gli ultimi due comandi hanno lo stesso comportamento
Non so da quale versione di git funzioni, ma è quello che stai cercando:
git submodule update --recursive
Lo uso con git pull
anche per aggiornare il repository root:
git pull && git submodule update --recursive
Guarda http://lists.zerezo.com/git/msg674976.html che introduce un parametro --track
Le risposte di cui sopra sono buone, tuttavia abbiamo usato git-hook per renderlo più semplice, ma risulta che in git 2.14 , puoi impostare git config submodule.recurse
su true per abilitare l'aggiornamento dei sottomoduli quando si tira nel tuo repository git.
Ciò avrà l'effetto collaterale di spingere tutti i cambiamenti dei sottomoduli che hai se sono comunque sui rami, ma se hai già bisogno di quel comportamento già questo potrebbe fare il lavoro.
Può essere fatto usando:
git config submodule.recurse true
Git per Windows 2.6.3 :
git submodule update --rebase --remote
L'ho fatto adattando gahooa 's risposta sopra :
Integralo con un git [alias]
...
Se il tuo progetto genitore ha qualcosa del genere in .gitmodules
:
[submodule "opt/submodules/solarized"]
path = opt/submodules/solarized
url = git@github.com:altercation/solarized.git
[submodule "opt/submodules/intellij-colors-solarized"]
path = opt/submodules/intellij-colors-solarized
url = git@github.com:jkaving/intellij-colors-solarized.git
Aggiungi qualcosa di simile all'interno del tuo .gitconfig
[alias]
updatesubs = "!sh -c \"git submodule init && git submodule update && git submodule status\" "
Quindi, per aggiornare i sottomoduli, eseguire:
git updatesubs
Ne ho un di esempio in il mio repo setup ambiente .
Ecco la riga di comando per estrarre da tutti i tuoi repository git che siano o meno sottomoduli:
ROOT=$(git rev-parse --show-toplevel 2> /dev/null)
find "$ROOT" -name .git -type d -execdir git pull -v ';'
Se lo esegui nel tuo repository git principale, puoi sostituire " $ ROOT "
in .
.
Tutto quello che devi fare ora è un semplice git checkout
Assicurati solo di abilitarlo tramite questa configurazione globale: git config --global submodule.recurse true
Dal livello superiore nel repository:
git submodule foreach git checkout develop
git submodule foreach git pull
Questo cambierà tutti i rami per sviluppare e tirare gli ultimi
Penso che dovrai fare uno script per farlo. Ad essere sincero, potrei installare Python per farlo in modo da poter usare os.walk
per cd
in ogni directory ed emettere i comandi appropriati. L'uso di Python o di un altro linguaggio di scripting, diverso dal batch, ti consentirebbe di aggiungere / rimuovere facilmente sottoprogetti senza dover modificare lo script.
Nota: non troppo semplice, ma fattibile e ha i suoi vantaggi unici.
Se si desidera clonare solo la revisione HEAD
di un repository e solo HEAD
di tutti i suoi sottomoduli (cioè per effettuare il checkout " trunk "), si può usa il seguente script Lua . A volte il semplice comando git submodule update --init --recursive --remote --no-fetch --depth = 1
può causare un errore git
irrecuperabile. In questo caso è necessario ripulire la sottodirectory della directory .git / modules
e clonare il sottomodulo manualmente usando il comando git clone --separate-git-dir
. L'unica complessità è scoprire URL , il percorso della directory .git
del sottomodulo e il percorso del sottomodulo nell'albero del superprogetto.
Nota: lo script viene testato solo sul repository https://github.com/boostorg/boost.git
. Le sue peculiarità: tutti i sottomoduli ospitati sullo stesso host e .gitmodules
contengono solo URL s relativi
-- 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