Apakšmoduļi
Git apakšmoduļi iegulda vienu repozitoriju citā. Vecākrepozitorija kokā apakšmodulis ir attēlots kā gitlink ieraksts (režīms 160000), kas norāda uz konkrētu komitu apakšmoduļa repozitorijā. Apakšmoduļa URL un ceļš ir deklarēti failā .gitmodules.
Jēdzieni
Vecākrepozitorija kokā:
100644 blob abc123... README.md
040000 tree def456... src/
160000 commit 789012... lib/external <-- gitlink entry (submodule)
Gitlink ierakstā ir norādīts, kurš apakšmoduļa komits ir jāizgūst. Pats apakšmoduļa repozitorijs atrodas šeit: .git/modules/<name>/
SubmoduleManager
use Pitmaster\Submodule\SubmoduleManager;
$manager = new SubmoduleManager(
$repo->objectDatabase(),
$repo->workDir(),
$repo->gitDir(),
);
Apakšmoduļu uzskaitīšana
$submodules = $manager->list();
foreach ($submodules as $sub) {
echo "{$sub->name}: {$sub->url} at {$sub->path}\n";
if ($sub->branch !== null) {
echo " tracks branch: {$sub->branch}\n";
}
}
Apakšmoduļa vērtības objekts
use Pitmaster\Submodule\Submodule;
$sub->name; // Submodule name (from .gitmodules section header)
$sub->path; // Path in the working tree
$sub->url; // Remote URL
$sub->branch; // Tracked branch (nullable)
.gitmodules parsēšana
Fails .gitmodules deklarē apakšmoduļa konfigurāciju:
[submodule "lib/external"]
path = lib/external
url = https://github.com/vendor/lib.git
branch = main
[submodule "tools/helper"]
path = tools/helper
url = https://github.com/vendor/helper.git
$content = file_get_contents('.gitmodules');
$submodules = SubmoduleManager::parseGitmodules($content);
foreach ($submodules as $sub) {
echo "{$sub->name} -> {$sub->url}\n";
}
Parsētājs apstrādā:
- Sadaļu galvenes:
[submodule "<name>"] - Atslēgu un vērtību pārus:
path = ...,url = ...,branch = ... - Komentārus (rindas, kas sākas ar
#) - Atstarpes un atkāpes
Ieraksti bez path un url tiek izlaisti. Vērtībām netiek noņemtas pēdiņas.
Gitlink ieraksti
Gitlink ieraksti ir koka ieraksti ar režīmu 160000. Tie norāda uz komitu (nevis koku vai blob) apakšmoduļa repozitorijā.
$tree = $repo->readObject($treeHash);
foreach ($tree->entries as $entry) {
if ($entry->isGitlink()) {
echo "Submodule at {$entry->name}: commit {$entry->hash->hex}\n";
}
}
TreeEntry noteikšana
$entry->isGitlink(); // true if mode is '160000'
$entry->mode; // '160000'
Apakšmoduļu inicializēšana
$manager->init();
Katram apakšmodulim, kas deklarēts .gitmodules:
- Izveido tukšu
.git/modules/<name>/direktoriju - Izveido apakšmoduļa ceļa direktoriju, ja tāda vēl nav
- Ieraksta
submodule.<name>.active = trueunsubmodule.<name>.urlfailā.git/config
Tas neko neiegūst un neizgūst no versiju vadības, kā arī neieraksta apakšmoduļa failu .git.
Apakšmoduļu atjaunināšana
$manager->update($repo->head()->tree);
Katram apakšmodulim, kas piesaistīts norādītajam kokam, update() kopē avota repozitorija git direktoriju uz .git/modules/<name>/, aizstāj apakšmoduļa darba failus ar avota failiem, ieraksta failu .git ar norādi uz moduļa direktoriju, iestata core.worktree un atdala HEAD norādītajā komitā.
Apakšmoduļa URL ir jābūt lokālam ceļam: absolūtam vai relatīvam pret vecākrepozitorija darba koku (git relatīvos URL atrisina attiecībā pret vecākrepozitorija attālā repozitorija URL). Ja URL ir shēma (https://...), tiek izraisīts RuntimeException('Submodule update currently supports only local paths: ...').
Pēc atjaunināšanas katru apakšmoduli var atvērt kā atsevišķu repozitoriju:
$subRepo = Pitmaster::open($repo->workDir() . '/lib/external');
Piesaistīto komitu pārbaude
$headCommit = $repo->head();
$pinnedId = $manager->pinnedCommit('lib/external', $headCommit->tree);
if ($pinnedId !== null) {
echo "lib/external is pinned to commit {$pinnedId->hex}\n";
}
Metode pinnedCommit() izstaigā koka hierarhiju, meklējot gitlink ierakstu norādītajā ceļā, un atgriež tā mērķa komita jaucējvērtību.
Apakšmoduļa statuss
$headCommit = $repo->head();
$statuses = $manager->status($headCommit->tree);
foreach ($statuses as $status) {
$expected = $status['expected'] ?? 'not pinned';
$actual = $status['actual'] ?? 'not initialized';
$dirty = $status['dirty'] ? ' (dirty)' : '';
echo "{$status['name']}: expected={$expected}, actual={$actual}{$dirty}\n";
}
Statusa lauki:
name: apakšmoduļa nosaukumspath: ceļš darba kokāexpected: vecākkokā piesaistītā komita jaucējvērtība (null, ja nav)actual: pašreizējais apakšmoduļa HEAD (null, ja nav inicializēts)dirty: true, ja abi komiti ir zināmi un atšķiras. Izmaiņas apakšmoduļa darba kokā netiek pārbaudītas.
Direktoriju struktūra
project/
.git/
modules/
lib/
external/ # Submodule's actual git directory (.git/modules/<name>)
HEAD
objects/
refs/
...
.gitmodules # Submodule declarations
lib/
external/
.git # File: "gitdir: ../../.git/modules/lib/external"
src/
README.md
src/
README.md
Apakšmoduļa darbplūsma
// 1. Open the parent repo
$repo = Pitmaster::open('/path/to/project');
// 2. List submodules
$manager = new SubmoduleManager(
$repo->objectDatabase(),
$repo->workDir(),
$repo->gitDir(),
);
$submodules = $manager->list();
// 3. Populate the submodules pinned at HEAD (local source paths only)
$manager->update($repo->head()->tree);
// 4. Check status
$statuses = $manager->status($repo->head()->tree);
// 5. Open a submodule as its own repo
$subRepo = Pitmaster::open($repo->workDir() . '/lib/external');
$subHead = $subRepo->head();
echo "Submodule HEAD: {$subHead->id->hex}\n";