Pāriet uz saturu

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ā:

Kods
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

PHP
use Pitmaster\Submodule\SubmoduleManager;

$manager = new SubmoduleManager(
    $repo->objectDatabase(),
    $repo->workDir(),
    $repo->gitDir(),
);

Apakšmoduļu uzskaitīšana

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

PHP
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:

Ini
[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
PHP
$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 ir koka ieraksti ar režīmu 160000. Tie norāda uz komitu (nevis koku vai blob) apakšmoduļa repozitorijā.

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

PHP
$entry->isGitlink();  // true if mode is '160000'
$entry->mode;         // '160000'

Apakšmoduļu inicializēšana

PHP
$manager->init();

Katram apakšmodulim, kas deklarēts .gitmodules:

  1. Izveido tukšu .git/modules/<name>/ direktoriju
  2. Izveido apakšmoduļa ceļa direktoriju, ja tāda vēl nav
  3. Ieraksta submodule.<name>.active = true un submodule.<name>.url failā .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

PHP
$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:

PHP
$subRepo = Pitmaster::open($repo->workDir() . '/lib/external');

Piesaistīto komitu pārbaude

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

PHP
$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 nosaukums
  • path: 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

Kods
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

PHP
// 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";