Birleştirme
Pitmaster, git merge gibi dalları üç yönlü birleştirme yöntemiyle birleştirir. İleri sarma fırsatlarını algılar, birleştirme tabanlarını hesaplar, ağaç ve içerik düzeyinde birleştirmeler yapar ve dosyalarda çakışma olduğunda standart çakışma işaretçileri oluşturur.
Temel birleştirme
$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 sınıfı, salt okunur bir değer nesnesidir:
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)
Birleştirme çakışmalar nedeniyle durduğunda çakışma durumu dizine ve çalışma ağacına yazılır. Dosyaları çözün, add() komutunu çalıştırın ve $repo->mergeContinue() çağrısını yapın ya da birleştirme öncesi duruma dönmek için $repo->mergeAbort() çağrısını yapın.
Birleştirmeden önce yerel değişiklikleri kaydedin veya saklayın: birleştirme, çalışma ağacını sonuçtan yeniden oluşturur ve izlenen dosyalardaki kaydedilmemiş değişikliklerin üzerine yazar (#2).
İleri sarma birleştirmeleri
Geçerli HEAD, hedef dalın atasıysa Pitmaster ileri sarma birleştirmesi yapar: birleştirme kaydı oluşturmadan HEAD'i hedef kayda taşır.
Before: After fast-forward:
A---B (main) A---B---C---D (main)
\
C---D (feature)
$result = $repo->merge('feature');
// $result->clean === true
// $result->commitId points to D
// No merge commit created
Ters durum henüz algılanmıyor: HEAD'in zaten içerdiği bir dalı birleştirmek, "Zaten güncel" bildirmek yerine ağacı değişmemiş yeni bir birleştirme kaydı oluşturur (#6).
Üç yönlü birleştirme
Dallar birbirinden ayrıştığında Pitmaster üç yönlü birleştirme yapar:
- Birleştirme tabanını bulun (en yakın ortak ata)
- Tabanı bizimkine ve tabanı onlarınkine ağaç düzeyinde karşılaştırın
- Her iki dalda da değiştirilen her dosya için içerik düzeyinde birleştirme yapın
- İki ebeveynli bir birleştirme kaydı oluşturun
Before: After merge:
C---D (feature) C---D
/ / \
A---B---E---F (main) A---B---E---F---G (main)
Birleştirme tabanı
Birleştirme tabanı, iki kaydın en yakın ortak atasıdır. Pitmaster bunu kayıt grafiğinde gezinerek bulur. Birden fazla birleştirme tabanı olduğunda (çapraz geçmiş), merge() bunları önce birleştirir ve sonucu taban olarak kullanır.
$base = $repo->mergeBase(
$repo->resolve('main'),
$repo->resolve('feature/login'),
);
if ($base !== null) {
echo "Common ancestor: {$base->hex}\n";
}
MergeBase algoritmasına doğrudan erişim için:
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);
Dal birleştirme denetimi
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
}
Çakışma işaretçileri
Bir dosya her iki dalda değiştirilmişse ve değişiklikler çakışıyorsa Pitmaster standart çakışma işaretçileri oluşturur. merge() tarafları HEAD ve birleştirilen dalın adıyla etiketler:
<<<<<<< HEAD
return $this->value + 1;
=======
return $this->value * 2;
>>>>>>> feature
ConflictMarker sınıfı, iki sürümü işaretçilerin içine alır:
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');
İçerik düzeyinde üç yönlü birleştirme
ThreeWayMerge sınıfı blob içeriğini (dosyaları değil) birleştirir:
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
Üç dizeyi (taban sürümü, bizim sürümümüz ve onların sürümü), isteğe bağlı etiketleri ve bir çakışma stilini alır (varsayılan olarak 'merge', taban bölümünü eklemek için 'diff3').
Birleştirme stratejileri
Özyinelemeli birleştirme
Varsayılan strateji olan $repo->merge($branch), birden fazla birleştirme tabanı içeren çapraz geçmişleri işler. CLI, bu strateji için -s ort ve -s recursive değerlerini de kabul eder.
Bizimki birleştirmesi
HEAD'in ağacını değiştirmeden tutan bir birleştirme kaydı oluşturur. Değişiklikleri dahil etmeden dal geçmişini korumak için kullanışlıdır.
$result = $repo->merge('feature/old', 'ours');
Octopus birleştirmesi
İki veya daha fazla dalı tek bir birleştirme kaydında birleştirir. Herhangi bir dalda çakışma varsa, birleştirme durumu yazmadan veya kayıt oluşturmadan temiz olmayan bir sonuç döndürür.
$result = $repo->mergeOctopus(['feature/a', 'feature/b', 'feature/c']);
Pitmaster\Merge içindeki RecursiveMerge, OursMerge ve OctopusMerge sınıfları içerik düzeyinde yardımcı araçlardır; Repository yukarıdaki stratejileri kendisi uygular.
Rerere (kaydedilmiş çözümü yeniden kullanma)
Pitmaster, çözümleri git'nin rr-cache düzeninde saklayan bağımsız bir Rerere sınıfı içerir:
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() bu sınıfı çağırmaz: çözümler yalnızca kodunuz bunu yaptığında kaydedilir ve yeniden uygulanır. isEnabled(), .git/config içinde rerere.enabled = true düz metnini arar ve git config rerere.enabled true tarafından yazılan [rerere] bölümünü tanımaz (#20).
Ağaç düzeyinde birleştirme akışı
Birleştirme işleminin tamamı:
MergeBase::findAll()ortak ataları bulur- Taban, bizim ve onların ağaçları yol yol karşılaştırılır
- Yalnızca bir dalda değiştirilen dosyalar için: bu değişiklik alınır
- Her iki dalda da değiştirilen dosyalar için:
- İkisi de aynı şekilde değiştirilmişse: ikisi de aynı sonucu verdiğinden herhangi biri alınır
- Değişiklikler farklıysa: içerikte
ThreeWayMerge::merge()çalıştırılır
- Tüm birleştirmeler temizse: birleştirilmiş ağacı oluşturun ve birleştirme kaydı yaratın
- Herhangi bir çakışma varsa:
MergeResultile çakışma yollarını içerenclean = falsedöndürülür
CLI kullanımı
./vendor/bin/pitmaster merge feature/login
Başarılı olduğunda çıktı:
Merge successful.
Çakışma çıktısı:
CONFLICT in: src/File.php, src/Other.php