Pereiti prie turinio

Sujungimas

Pitmaster sujungia šakas trijų krypčių metodu, kaip git merge. Aptinka greitojo perslinkimo galimybes, apskaičiuoja sujungimo bazes, sujungia medžius ir turinį bei failams konfliktuojant įterpia standartinius konfliktų žymeklius.

Pagrindinis sujungimas

PHP
$result = $repo->merge('feature/login');

if ($result->clean) {
    echo "Merged successfully: {$result->commitId->hex}\n";
} else {
    echo "Conflicts:\n";
    foreach ($result->conflictPaths as $path) {
        echo "  {$path}\n";
    }
}

MergeResult

MergeResult klasė yra tik skaitomas reikšmės objektas:

PHP
use Pitmaster\Merge\MergeResult;

$result->clean;           // bool: true if merge completed without conflicts
$result->commitId;        // ?ObjectId: the merge commit (null if conflicts)
$result->conflictPaths;   // array: list of file paths with conflicts
$result->mergedContents;  // array: path => content with conflict markers (if conflicts)

Kai sujungimas sustoja dėl konfliktų, konfliktų būsena įrašoma į indeksą ir darbinį medį. Išspręskite konfliktus failuose, juos add() ir iškvieskite $repo->mergeContinue() arba iškvieskite $repo->mergeAbort(), kad atkurtumėte būseną prieš sujungimą.

Prieš sujungdami patvirtinkite arba padėkite į saugyklą vietinius pakeitimus: sujungimas iš naujo sukuria darbinį medį pagal rezultatą ir perrašo nepatvirtintus sekamų failų pakeitimus (#2).

Greitojo perslinkimo sujungimai

Kai dabartinis HEAD yra tikslinės šakos protėvis, Pitmaster atlieka greitojo perslinkimo sujungimą: tiesiog perkelia HEAD į tikslinį įrašą, nesukurdama sujungimo įrašo.

Kodas
Before:         After fast-forward:

A---B (main)    A---B---C---D (main)
     \
      C---D (feature)
PHP
$result = $repo->merge('feature');
// $result->clean === true
// $result->commitId points to D
// No merge commit created

Atvirkštinis atvejis dar neaptinkamas: sujungus šaką, kurią HEAD jau apima, sukuriamas naujas sujungimo įrašas su nepakitusiu medžiu, užuot pranešus „Already up to date“ (#6).

Trijų krypčių sujungimas

Kai šakų istorijos išsiskiria, Pitmaster atlieka trijų krypčių sujungimą:

  1. Rasti sujungimo bazę (artimiausią bendrą protėvį)
  2. Palyginti bazę su mūsų ir su jų šakomis medžių lygmeniu
  3. Kiekvienam failui, pakeistam abiejose šakose, atlikti turinio lygmens sujungimą
  4. Sukurti sujungimo įrašą su dviem tėviniais įrašais
Kodas
Before:              After merge:

      C---D (feature)         C---D
     /                       /     \
A---B---E---F (main)   A---B---E---F---G (main)

Sujungimo bazė

Sujungimo bazė yra naujausias bendras dviejų įrašų protėvis. Pitmaster ją randa eidama įrašų grafu. Jei sujungimo bazių yra kelios (kryžminė istorija), merge() pirmiausia jas sujungia, o rezultatą naudoja kaip bazę.

PHP
$base = $repo->mergeBase(
    $repo->resolve('main'),
    $repo->resolve('feature/login'),
);

if ($base !== null) {
    echo "Common ancestor: {$base->hex}\n";
}

Tiesioginei prieigai prie MergeBase algoritmo:

PHP
use Pitmaster\Merge\MergeBase;

$finder = new MergeBase($repo->objectDatabase());
$base = $finder->find($commitA, $commitB);

// All merge bases (criss-cross histories can have more than one)
$bases = $finder->findAll($commitA, $commitB);

// Check ancestry
$isAncestor = $finder->isAncestor($oldCommit, $newCommit);

Šakų sujungimo tikrinimas

PHP
if ($repo->isBranchMerged('feature/done')) {
    // All commits in feature/done are reachable from default branch
    $repo->deleteBranch('feature/done');
}

// Check against a specific target
if ($repo->isBranchMerged('feature/done', 'develop')) {
    // Merged into develop
}

Konfliktų žymekliai

Kai failas pakeičiamas abiejose šakose ir pakeitimai persidengia, Pitmaster įterpia standartinius konfliktų žymeklius. merge() pažymi puses HEAD ir sujungtos šakos pavadinimu:

Kodas
<<<<<<< HEAD
    return $this->value + 1;
=======
    return $this->value * 2;
>>>>>>> feature

ConflictMarker klasė apgaubia dvi versijas žymekliais:

PHP
use Pitmaster\Merge\ConflictMarker;

$marked = ConflictMarker::mark($oursContent, $theirsContent, 'HEAD', 'feature');

// diff3 style, with the base section
$marked = ConflictMarker::mark($oursContent, $theirsContent, 'HEAD', 'feature', $baseContent, 'base');

Trijų krypčių sujungimas turinio lygmeniu

ThreeWayMerge klasė sujungia blob turinį (ne failus):

PHP
use Pitmaster\Merge\ThreeWayMerge;

$result = ThreeWayMerge::merge($baseContent, $oursContent, $theirsContent, 'HEAD', 'feature');

$result['content'];   // merged text, with conflict markers if needed
$result['clean'];     // true when nothing conflicted
$result['conflicts']; // number of conflict regions

Ji priima tris eilutes (bazinę versiją, mūsų versiją ir jų versiją), pasirinktines etiketes ir konflikto stilių (pagal numatytuosius nustatymus 'merge', o 'diff3' įtraukia bazinę skiltį).

Sujungimo strategijos

Rekursinis sujungimas

Numatytoji strategija ($repo->merge($branch)) apdoroja kryžmines sujungimų istorijas su keliomis sujungimo bazėmis. Jai CLI taip pat priima -s ort ir -s recursive.

Mūsų pusės sujungimas

Sukuria sujungimo įrašą, paliekantį HEAD medį nepakeistą. Naudinga šakų istorijai palaikyti neįtraukiant pakeitimų.

PHP
$result = $repo->merge('feature/old', 'ours');

Aštuonkojo sujungimas

Sujungia dvi ar daugiau šakų į vieną sujungimo įrašą. Jei kurioje nors šakoje kyla konfliktų, grąžinamas nešvarus rezultatas, neįrašant sujungimo būsenos ir nesukuriant įrašo.

PHP
$result = $repo->mergeOctopus(['feature/a', 'feature/b', 'feature/c']);

Pitmaster\Merge esančios RecursiveMerge, OursMerge ir OctopusMerge klasės yra turinio lygmens pagalbinės priemonės; Repository pačios įgyvendina pirmiau nurodytas strategijas.

Rerere (pakartotinis įrašyto sprendimo panaudojimas)

Pitmaster turi atskirą Rerere klasę, kuri saugo sprendimus git rr-cache išdėstymu:

PHP
use Pitmaster\Merge\Rerere;

$rerere = new Rerere($repo->gitDir());

if ($rerere->isEnabled()) {                     // rerere.enabled = true in .git/config
    $rerere->record($conflicted, $resolved);    // remember a resolution
    $resolved = $rerere->resolve($conflicted);  // replay it, or null
}

merge() jos neiškviečia: sprendimai įrašomi ir pakartojami tik tada, kai taip nurodo jūsų kodas. isEnabled() ieško pažodinio teksto rerere.enabled = true faile .git/config ir neatpažįsta [rerere] skilties, kurią įrašo git config rerere.enabled true (#20).

Sujungimo eiga medžių lygmeniu

Visas sujungimo procesas:

  1. MergeBase::findAll() nustato bendrus protėvius
  2. Pagrindinis, mūsų ir jų medžiai lyginami pagal kiekvieną kelią
  3. Failams, pakeistiems tik vienoje šakoje: pritaikomas tas pakeitimas
  4. Failams, pakeistiems abiejose šakose:
    • Jei pakeista vienodai: pritaikomas bet kuris variantas (jie sutampa)
    • Jei pakeitimai skiriasi: turiniui paleidžiamas ThreeWayMerge::merge()
  5. Jei visi sujungimai švarūs: sukuriamas sujungtas medis ir sujungimo įrašas
  6. Jei yra konfliktų: grąžinamas MergeResult su clean = false ir konfliktuojančiais keliais

CLI naudojimas

Shell
./vendor/bin/pitmaster merge feature/login

Išvestis sėkmės atveju:

Kodas
Merge successful.

Konflikto atveju pateikiama:

Kodas
CONFLICT in: src/File.php, src/Other.php