Ini karena keterbatasan algoritma asli. Saat menangani komit gabungan, algoritme asli menggunakan kriteria yang disederhanakan untuk memotong orang tua yang tidak terkait. Secara khusus, ia memeriksa, jika ada induk, yang memiliki pohon yang sama. Jika orang tua seperti itu ditemukan, itu akan menciutkan komit gabungan dan menggunakan komit induk sebagai gantinya, dengan asumsi bahwa orang tua lain memiliki perubahan yang tidak terkait dengan sub-pohon. Dalam beberapa kasus, hal ini akan mengakibatkan hilangnya bagian sejarah, yang memiliki perubahan aktual pada sub-pohon. Secara khusus itu akan menjatuhkan urutan komit, yang akan menyentuh sub-pohon, tetapi menghasilkan nilai sub-pohon yang sama.
Mari kita lihat contoh (yang dapat Anda gandakan dengan mudah) untuk lebih memahami cara kerjanya. Pertimbangkan sejarah berikut (format barisnya adalah: commit [tree] subject):
% 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
Dalam contoh ini, kita akan membagi dir
. Komit D
dan E
memiliki pohon yang sama z
, karena kita memiliki komit C
, yang dibatalkan komit B
, jadi B-C
urutan tidak melakukan apa dir
pun meskipun ada perubahan padanya.
Sekarang mari lakukan pemisahan. Pertama kita berpisah saat komit 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
Selanjutnya kita berpisah saat komit E
.
% git log `git subtree split -P dir E` ...
* D' [z'] add dir/file2.txt
* A' [w'] add dir/file1.txt
Ya, kami kehilangan dua komitmen. Ini menghasilkan kesalahan saat mencoba mendorong pemisahan kedua, karena tidak memiliki dua commit tersebut, yang sudah masuk ke asalnya.
Biasanya Anda dapat mentolerir kesalahan ini dengan menggunakan push --force
, karena komit yang dihapus umumnya tidak akan memiliki informasi penting di dalamnya. Dalam jangka panjang, bug perlu diperbaiki, sehingga riwayat terpisah benar-benar memiliki semua komitmen, yang menyentuh dir
, seperti yang diharapkan. Saya mengharapkan perbaikan untuk menyertakan analisis yang lebih dalam tentang komitmen orang tua untuk dependensi tersembunyi.
Sebagai referensi, berikut adalah bagian dari kode asli, yang bertanggung jawab atas perilaku tersebut.
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