Git 2.18 (Q2 2018) akan sangat meningkatkan --preserve-merge
opsi dengan menambahkan opsi baru.
" git rebase
" belajar " --rebase-merges
" untuk mentransplantasikan seluruh topologi grafik commit di tempat lain .
(Catatan: Git 2.22, Q2 2019, sebenarnya sudah usang --preserve-merge
, dan Git 2.25, Q1 2020, berhenti mengiklankannya di git rebase --help
keluaran " " )
Lihat komit 25cff9f , komit 7543f6f , komit 1131ec9 , komit 7ccdf65 , komit 537e7d6 , komit a9be29c , komit 8f6aed7 , komit 1644c73 , komit d1e8b01 , komit 4c68e7d , komit 9055e40 , komit cb5206e , komit a01c2a5 , komit 2f6b1d1 , komit bf5c057 (25 Apr 2018) oleh Johannes Schindelin ( dscho
) .
Lihat commit f431d73 (25 Apr 2018) oleh Stefan Beller ( stefanbeller
) .
Lihat komit 2429335 (25 Apr 2018) oleh Phillip Wood ( phillipwood
) .
(Digabung oleh Junio C Hamano - gitster
- di komit 2c18e6a , 23 Mei 2018)
pull
: terima --rebase-merges
untuk membuat ulang topologi cabang
Mirip dengan preserve
mode hanya lewat --preserve-merges
opsi ke rebase
perintah, merges
mode hanya melewati
--rebase-merges
opsi.
Ini akan memungkinkan pengguna untuk dengan mudah rebase topologi komit non-sepele saat menarik komit baru, tanpa meratakannya.
git rebase
halaman buku panduan sekarang memiliki bagian lengkap yang didedikasikan untuk memunculkan kembali sejarah dengan penggabungan .
Ekstrak:
Ada alasan yang sah mengapa pengembang mungkin ingin membuat kembali komitmen gabungan: untuk menjaga struktur cabang (atau "melakukan topologi") ketika bekerja pada beberapa cabang yang saling terkait.
Dalam contoh berikut, pengembang bekerja pada cabang topik yang refactors cara tombol didefinisikan, dan pada cabang topik lain yang menggunakan refactoring itu untuk menerapkan tombol "Laporkan bug".
Output dari git log --graph --format=%s -5
mungkin terlihat seperti ini:
* Merge branch 'report-a-bug'
|\
| * Add the feedback button
* | Merge branch 'refactor-button'
|\ \
| |/
| * Use the Button class for all buttons
| * Extract a generic Button class from the DownloadButton one
Pengembang mungkin ingin mengubah komitmennya ke yang lebih baru master
sambil mempertahankan topologi cabang, misalnya ketika cabang topik pertama diharapkan akan diintegrasikan ke dalam yang master
jauh lebih awal daripada yang kedua, katakanlah, untuk menyelesaikan konflik gabungan dengan perubahan pada
DownloadButton
kelas yang dibuat itu menjadi master
.
Rebase ini dapat dilakukan menggunakan --rebase-merges
opsi.
Lihat komit 1644c73 untuk contoh kecil:
rebase-helper
--make-script
: memperkenalkan bendera untuk rebase penggabungan
Sequencer baru saja mempelajari perintah-perintah baru yang dimaksudkan untuk menciptakan kembali struktur cabang ( serupa dengan semangat --preserve-merges
, tetapi dengan desain yang tidak terlalu rusak ).
Mari kita izinkan rebase--helper
untuk membuat daftar todo memanfaatkan perintah ini, dipicu oleh --rebase-merges
opsi baru .
Untuk topologi komit seperti ini (di mana HEAD menunjuk ke C):
- A - B - C (HEAD)
\ /
D
daftar todo yang dihasilkan akan terlihat seperti ini:
# branch D
pick 0123 A
label branch-point
pick 1234 D
label D
reset branch-point
pick 2345 B
merge -C 3456 D # C
Apa bedanya dengan --preserve-merge
?
Commit 8f6aed7 menjelaskan:
Sekali waktu, pengembang di sini berpikir: bukankah lebih baik jika, katakanlah, Git untuk tambalan Windows di atas core Git dapat direpresentasikan sebagai setumpuk cabang, dan di rebase di atas core Git untuk mempertahankan serangkaian patch seri cherry-pick'able?
Upaya asli untuk menjawab ini adalah: git rebase --preserve-merges
.
Namun, percobaan itu tidak pernah dimaksudkan sebagai opsi interaktif, dan itu hanya didukung oleh piggy git rebase --interactive
karena implementasi perintah itu terlihat sudah sangat, sangat akrab: itu dirancang oleh orang yang sama yang mendesain --preserve-merges
: Anda benar-benar.
Dan oleh "Anda benar-benar", penulis menyebut dirinya: Johannes Schindelin ( dscho
) , yang merupakan alasan utama (dengan beberapa pahlawan lainnya - Hannes, Steffen, Sebastian, ...) bahwa kami memiliki Git Untuk Windows (meskipun kembali pada hari - 2009 - itu tidak mudah ).
Dia bekerja di Microsoft sejak September 2015 , yang masuk akal mengingat Microsoft sekarang banyak menggunakan Git dan membutuhkan layanannya.
Itu tren dimulai pada 2013 sebenarnya, dengan TFS . Sejak itu, Microsoft mengelola repositori Git terbesar di planet ini ! Dan, sejak Oktober 2018, Microsoft mengakuisisi GitHub .
Anda dapat melihat Johannes berbicara dalam video ini untuk Git Merge 2018 pada April 2018.
Beberapa waktu kemudian, beberapa pengembang lain (saya melihat Anda, Andreas! ;-)) memutuskan bahwa itu akan menjadi ide yang baik untuk memungkinkan --preserve-merges
untuk digabungkan dengan --interactive
(dengan peringatan!) Dan pengelola Git (baiklah, pengelola Git sementara selama Junio tidak ada, itu disetujui, dan saat itulah kemewahan --preserve-merges
desain mulai berantakan agak cepat dan tidak glamor.
Di sini Jonathan berbicara tentang Andreas Schwab dari Suse.
Anda dapat melihat beberapa diskusi mereka pada tahun 2012 .
Alasannya? Dalam --preserve-merges
mode, orang tua dari komit gabungan (atau dalam hal ini, komit apa pun ) tidak dinyatakan secara eksplisit, tetapi
tersirat oleh nama komit yang diteruskan ke pick
perintah .
Ini membuatnya tidak mungkin, misalnya, untuk menyusun ulang komitmen .
Belum lagi untuk memindahkan komit antar cabang atau, dewa melarang, untuk membagi cabang topik menjadi dua.
Sayangnya, kekurangan ini juga mencegah mode itu (yang tujuan awalnya adalah untuk melayani Git untuk kebutuhan Windows, dengan harapan tambahan bahwa mungkin bermanfaat bagi orang lain juga) dari melayani Git untuk kebutuhan Windows.
Lima tahun kemudian, ketika menjadi benar-benar tidak dapat dipertahankan untuk memiliki satu seri tambalan yang besar dan sulit dijangkau, sebagian terkait, sebagian tambalan yang tidak terkait di Git untuk Windows yang diubah kembali ke tag inti Git dari waktu ke waktu (mendapatkan kemarahan pengembang yang tidak selayaknya diterima) dari git-remote-hg
seri naas
yang pertama kali usang Git untuk pendekatan bersaing Windows, hanya untuk ditinggalkan tanpa pengelola kemudian) benar-benar tidak bisa dipertahankan, " Git garden shears " lahir : sebuah skrip, dukungan babi di atas rebase interaktif, yang pertama-tama akan menentukan topologi cabang dari tambalan-tambalan yang akan di-rebase, membuat daftar pseudo todo untuk pengeditan lebih lanjut, mengubah hasilnya menjadi daftar todo yang nyata (menggunakan banyakexec
perintah untuk "mengimplementasikan" perintah daftar todo yang hilang) dan akhirnya menciptakan kembali seri tambalan di atas komit basis baru.
(Skrip gunting taman Git direferensikan dalam tambalan ini di commit 9055e40 )
Itu pada tahun 2013.
Dan butuh sekitar tiga minggu untuk membuat desain dan mengimplementasikannya sebagai skrip out-of-tree. Tak perlu dikatakan, implementasi membutuhkan beberapa tahun untuk stabil, sementara desain itu sendiri terbukti masuk akal.
Dengan tambalan ini, kebaikan gunting kebun Git muncul dengan git
rebase -i
sendirinya .
Melewati --rebase-merges
opsi akan menghasilkan daftar todo yang dapat dipahami dengan mudah, dan di mana jelas bagaimana mengatur ulang komit .
Cabang baru dapat diperkenalkan dengan memasukkan label
perintah dan panggilan merge <label>
.
Dan sekali mode ini akan menjadi stabil dan diterima secara universal, kita bisa mencela kesalahan desain itu--preserve-merges
.
Git 2.19 (Q3 2018) meningkatkan --rebase-merges
opsi baru dengan membuatnya berfungsi --exec
.
Opsi " --exec
" untuk " git rebase --rebase-merges
" menempatkan perintah exec di tempat yang salah, yang telah diperbaiki.
Lihat komit 1ace63b (09 Agustus 2018), dan komit f0880f7 (06 Agt 2018) oleh Johannes Schindelin ( dscho
) .
(Digabung oleh Junio C Hamano - gitster
- dalam commit 750eb11 , 20 Agu 2018)
rebase --exec
: membuatnya bekerja dengan --rebase-merges
Idenya --exec
adalah untuk menambahkan exec
panggilan setelah masing-masing pick
.
Sejak pengenalan fixup!
/ s quash!
komit, ide ini diperluas untuk diterapkan pada "pick, kemungkinan diikuti oleh fixup / squash chain", yaitu eksekutif tidak akan disisipkan antara a pick
dan salah satu dari baris fixup
atau korespondennya
squash
.
Implementasi saat menggunakan trik kotor untuk mencapai itu: mengasumsikan bahwa ada hanya memilih / fixup / squash perintah, dan kemudian
memasukkan satu exec
baris sebelum pick
tapi pertama, dan menambahkan satu akhir.
Dengan daftar todo yang dihasilkan oleh git rebase --rebase-merges
, implementasi sederhana ini menunjukkan masalahnya: itu menghasilkan hal yang salah ketika ada label
, reset
dan merge
perintah.
Mari kita ubah implementasi untuk melakukan apa yang kita inginkan: cari
pick
baris, lewati semua rantai fixup / squash, dan kemudian masukkan exec
baris . Busa, bilas, ulangi.
Catatan: kami bersusah payah untuk menyisipkan sebelum baris komentar bila memungkinkan, karena komit kosong diwakili oleh garis pick yang dikomentari (dan kami ingin menyisipkan baris exec pick sebelumnya sebelum baris seperti itu, bukan sesudahnya).
Saat melakukannya, tambahkan juga exec
baris setelah merge
perintah, karena mereka serupa semangatnya dengan pick
perintah: mereka menambahkan komit baru.
Git 2.22 (Q2 2019) memperbaiki penggunaan referensi / ditulis ulang / hierarki untuk menyimpan status perantara rebase, yang secara inheren membuat hierarki per worktree.
Lihat komit b9317d5 , komit 90d31ff , komit 09e6564 (07 Mar 2019) oleh Nguyễn Thái Ngọc Duy ( pclouds
) .
(Digabung oleh Junio C Hamano - gitster
- dalam komit 917f2cd , 09 Apr 2019)
Pastikan ref / ditulis ulang / adalah per-worktree
a9be29c (sequencer: make ref yang dihasilkan oleh label
perintah worktree-local, 2018-04-25, Git 2.19) ditambahkan refs/rewritten/
sebagai ruang referensi per-worktree.
Sayangnya (salah saya) ada beberapa tempat yang perlu diperbarui untuk memastikan itu benar-benar per-worktree.
- add_per_worktree_entries_to_dir()
diperbarui untuk memastikan tampilan daftar ref pada per-worktree refs/rewritten/
bukan per-repo satu.
common_list[]
diperbarui sehingga git_path()
mengembalikan lokasi yang benar. Ini termasuk " rev-parse --git-path
".
Kekacauan ini dibuat oleh saya.
Saya mulai mencoba memperbaikinya dengan perkenalan di refs/worktree,
mana semua referensi akan per-kerja tanpa perawatan khusus.
Ref / ditulis ulang yang disayangkan datang sebelum ref / worktree sehingga hanya ini yang bisa kita lakukan.
Dengan Git 2.24 (Q4 2019), " git rebase --rebase-merges
" belajar untuk mendorong berbagai strategi penggabungan dan memberikan opsi khusus strategi kepada mereka.
Lihat commit 476998d (04 Sep 2019) oleh Elijah Newren ( newren
) .
Lihat komit e1fac53 , komit a63f990 , komit 5dcdd74 , komit e145d99 , komit 4e6023b , komit f67336d , komit a9c7107 , komit b8c6f24 , komit d51b771 , komit c248d32 , komit 8c1e240 , komit 5efed0e , komit 68b54f6 , komit 2e7bbac , komit 6180b20 , berkomitmen d5b581f (31 Jul 2019) olehJohannes Schindelin ( dscho
) .
(Digabung oleh Junio C Hamano - gitster
- dalam komit 917a319 , 18 Sep 2019)
Dengan Git 2.25 (Q1 2020), logika yang digunakan untuk memberi tahu worktree local dan repositori global terpisah adalah tetap, untuk memfasilitasi penggabungan-penggabungan.
Lihat komit f45f88b , komit c72fc40 , komit 8a64881 , komit 7cb8c92 , komit e536b1f (21 Okt 2019) oleh SZEDER Gábor ( szeder
) .
(Digabung oleh Junio C Hamano - gitster
- di commit db806d7 , 10 Nov 2019)
path.c
: jangan panggil match
fungsi tanpa nilai dalamtrie_find()
Ditandatangani oleh: SZEDER Gábor
'log / ref' bukan jalur khusus pohon yang berfungsi, tetapi sejak commit b9317d55a3 (Pastikan ref / ditulis ulang / adalah per-worktree, 2019-03-07, v2.22.0-rc0) ' git rev-parse --git-path
' telah mengembalikan jalur palsu jika ada trailing ' /
':
$ git -C WT/ rev-parse --git-path logs/refs --git-path logs/refs/
/home/szeder/src/git/.git/logs/refs
/home/szeder/src/git/.git/worktrees/WT/logs/refs/
Kami menggunakan a trie
struktur data untuk memutuskan secara efisien apakah jalur milik dir umum atau bekerja khusus pohon.
Seperti yang terjadi, b9317d55a3 memicu bug yang setua trie
implementasi itu sendiri, ditambahkan di 4e09cf2acf (" path
: optimalkan pemeriksaan direktori umum", 2015-08-31, Git v2.7.0-rc0 - gabung tercantum dalam batch # 2 ).
Menurut komentar yang menguraikan trie_find()
, itu seharusnya hanya memanggil fungsi kecocokan yang diberikan 'fn' untuk awalan "/ -atau- \ 0 yang diakhiri dari kunci yang mengandung tiga nilai".
Ini tidak benar: ada tiga tempat di mana trie_find () memanggil fungsi pencocokan, tetapi salah satunya tidak ada pemeriksaan untuk keberadaan nilai.
b9317d55a3 menambahkan dua kunci baru ke trie
:
- '
logs/refs/rewritten
', dan
- '
logs/refs/worktree
', di sebelah yang sudah ada ' logs/refs/bisect
'.
Ini menghasilkan trie
simpul dengan jalur ' logs/refs/
', yang tidak ada sebelumnya, dan yang tidak memiliki nilai terlampir.
Kueri untuk ' logs/refs/
' menemukan simpul ini dan kemudian mengenai satu situs panggilan match
fungsi yang tidak memeriksa keberadaan nilai, dan dengan demikian memanggil match
fungsi dengan NULL
nilai.
Ketika match
fungsi check_common()
dipanggil dengan NULL
nilai, itu mengembalikan 0, yang menunjukkan bahwa jalur yang diminta bukan milik direktori umum, akhirnya menghasilkan jalur palsu yang ditunjukkan di atas.
Tambahkan kondisi yang hilang ke trie_find()
sehingga tidak akan pernah memanggil fungsi pertandingan dengan nilai yang tidak ada.
check_common()
maka tidak lagi harus memeriksa bahwa itu mendapat nilai non-NULL, jadi hapus kondisi itu.
Saya percaya bahwa tidak ada jalur lain yang dapat menyebabkan keluaran palsu yang serupa.
AFAICT satu-satunya kunci lain yang menghasilkan fungsi kecocokan yang dipanggil dengan NULL
nilai adalah ' co
' (karena tombol ' common
' dan ' config
').
Namun, karena mereka tidak berada dalam direktori yang termasuk dalam direktori umum, diharapkan dihasilkan jalur khusus pohon yang berfungsi.
git --rebase-merges
pada akhirnya akan menggantikan yang lamagit --preserve-merges
. Lihat jawaban saya di bawah ini