Bunun nedeni, orijinal algoritmanın sınırlandırılmasıdır. Birleştirme işlemlerini işlerken, orijinal algoritma ilgisiz üst öğeleri kesmek için basitleştirilmiş bir kriter kullanır. Özellikle, aynı ağaca sahip bir ebeveyn olup olmadığını kontrol eder. Böyle bir üst öğe bulunursa, diğer üst öğelerin alt ağaçla ilgisi olmayan değişikliklere sahip olduğunu varsayarak, birleştirme kesinleştirme işlemini daraltır ve bunun yerine üst işlemeyi kullanır. Bazı durumlarda bu, alt ağaçta gerçek değişikliklere sahip olan geçmişin bölümlerinin atılmasına neden olabilir. Özellikle, bir alt ağaca dokunan ancak aynı alt ağaç değeriyle sonuçlanan işlem dizilerini bırakacaktır.
Bunun nasıl çalıştığını daha iyi anlamak için (kolayca yeniden üretebileceğiniz) bir örnek görelim. Şu geçmişi düşünün (satır biçimi: commit [ağaç] konusu):
% git log --graph --decorate --pretty=oneline --pretty="%h [%t] %s"
* E [z] Merge branch 'master' into side-branch
|\
| * D [z] add dir/file2.txt
* | C [y] Revert "change dir/file1.txt"
* | B [x] change dir/file1.txt
|/
* A [w] add dir/file1.txt
Bu örnekte, ayrılıyoruz dir
. Taahhüt eder D
ve E
aynı ağaca z
sahip oluruz, çünkü kesinleştirmemiz vardır C
, bu da sonlandırmayı geri alır B
, bu yüzden B-C
dizi, dir
üzerinde değişiklikler olsa bile hiçbir şey yapmaz .
Şimdi bölme yapalım. İlk önce taahhüt üzerine ayrıldık C
.
% git log `git subtree split -P dir C` ...
* C' [y'] Revert "change dir/file1.txt"
* B' [x'] change dir/file1.txt
* A' [w'] add dir/file1.txt
Daha sonra taahhütte ayrılıyoruz E
.
% git log `git subtree split -P dir E` ...
* D' [z'] add dir/file2.txt
* A' [w'] add dir/file1.txt
Evet, iki kaydı kaybettik. Bu, ikinci bölünmeyi itmeye çalışırken hataya neden olur, çünkü zaten başlangıç noktasına giren bu iki işleme sahip değildir.
Genellikle bu hatayı kullanarak tolere edebilirsiniz push --force
, çünkü bırakılan taahhütler genellikle bunlarda kritik bilgiler içermez. Uzun vadede, hatanın düzeltilmesi gerekir, böylece bölünmüş geçmiş aslında tüm işlemlere sahip olur,dir
beklendiği gibi . Düzeltmenin, gizli bağımlılıklar için ebeveyn taahhütlerinin daha derin bir analizini içermesini beklerdim.
Referans için, orijinal kodun davranıştan sorumlu kısmı burada verilmiştir.
copy_or_skip()
...
for parent in $newparents; do
ptree=$(toptree_for_commit $parent) || exit $?
[ -z "$ptree" ] && continue
if [ "$ptree" = "$tree" ]; then
identical="$parent"
else
nonidentical="$parent"
fi
...
if [ -n "$identical" ]; then
echo $identical
else
copy_commit $rev $tree "$p" || exit $?
fi