Saya telah bertanya sebelumnya tentang bagaimana menghapus dua commit pertama dalam repositori git.
Walaupun solusinya agak menarik dan tidak terlalu membingungkan seperti beberapa hal lain di git, solusi tersebut masih sedikit seperti pepatah yang menyakitkan jika Anda perlu mengulangi prosedur ini berkali-kali selama pengembangan proyek Anda.
Jadi, saya lebih suka melewati rasa sakit hanya sekali, dan kemudian dapat selamanya menggunakan rebase interaktif standar.
Jadi, yang ingin saya lakukan adalah memiliki komit awal kosong yang hanya ada untuk tujuan yang pertama. Tidak ada kode, tidak apa-apa. Hanya mengambil ruang sehingga bisa menjadi basis untuk rebase.
Pertanyaan saya kemudian adalah, apakah memiliki repositori yang sudah ada, bagaimana cara memasukkan komit baru yang kosong sebelum yang pertama, dan menggeser orang lain ke depan?
Jawaban:
Ada 2 langkah untuk mencapai ini:
Kami akan menempatkan komit kosong yang baru di cabang sementara
newroot
untuk kenyamanan.1. Buat komit kosong baru
Ada beberapa cara Anda bisa melakukan ini.
Hanya menggunakan pipa ledeng
Pendekatan terbersih adalah dengan menggunakan pipa ledeng Git hanya untuk membuat komit secara langsung, yang menghindari menyentuh copy pekerjaan atau indeks atau cabang mana yang diperiksa, dll.
Buat objek pohon untuk direktori kosong:
Bungkus sebuah komit di sekitarnya:
Buat referensi untuk itu:
Anda tentu saja dapat mengatur ulang seluruh prosedur menjadi satu-liner jika Anda cukup tahu shell Anda.
Tanpa pipa ledeng
Dengan perintah porselen biasa, Anda tidak dapat membuat komit kosong tanpa memeriksa
newroot
cabang dan memperbarui indeks dan copy pekerjaan berulang kali, tanpa alasan yang bagus. Tetapi beberapa mungkin menemukan ini lebih mudah untuk dipahami:Perhatikan bahwa pada versi Git yang sangat lama yang tidak memiliki
--orphan
sakelarcheckout
, Anda harus mengganti baris pertama dengan ini:2. Tulis ulang riwayat untuk memulai dari komit kosong ini
Anda memiliki dua opsi di sini: rebasing, atau penulisan ulang riwayat bersih.
Rebasing
Ini memiliki sifat kesederhanaan. Namun, itu juga akan memperbarui nama dan tanggal committer pada setiap komit terakhir di cabang.
Juga, dengan beberapa riwayat kasus tepi, itu bahkan mungkin gagal karena menggabungkan konflik - terlepas dari kenyataan bahwa Anda rebasing ke komit yang tidak mengandung apa pun.
Menulis ulang sejarah
Pendekatan yang lebih bersih adalah menulis ulang cabang. Berbeda dengan dengan
git rebase
, Anda harus mencari komit yang dimulai dari cabang Anda:Penulisan ulang terjadi pada langkah kedua, jelas; itu langkah pertama yang perlu penjelasan. Apa yang
git replace
dilakukan itu memberi tahu Git bahwa setiap kali ia melihat referensi ke objek yang ingin Anda ganti, Git seharusnya melihat penggantian objek itu.Dengan
--graft
sakelar, Anda mengatakan sesuatu yang sedikit berbeda dari biasanya. Anda mengatakan belum memiliki objek pengganti, tetapi Anda ingin mengganti<currentroot>
objek komit dengan salinan dirinya sendiri kecuali komit induk pengganti haruslah yang terdaftar (yaitunewroot
komit ). Kemudiangit replace
lanjutkan dan buat komit ini untuk Anda, dan kemudian nyatakan komit itu sebagai pengganti komit asli Anda.Sekarang jika Anda melakukan
git log
, Anda akan melihat bahwa segala sesuatu sudah terlihat seperti yang Anda inginkan: cabang dimulainewroot
.Namun, perhatikan bahwa
git replace
sebenarnya tidak memodifikasi histori - juga tidak menyebar keluar dari repositori Anda. Itu hanya menambahkan redirect lokal ke repositori Anda dari satu objek ke objek lain. Artinya, tidak ada orang lain yang melihat efek dari penggantian ini - hanya Anda.Itu sebabnya
filter-branch
langkah ini perlu. Dengangit replace
Anda membuat salinan yang tepat dengan komitmen induk yang disesuaikan untuk komit root;git filter-branch
kemudian ulangi proses ini untuk semua komitmen berikut juga. Di situlah sejarah sebenarnya ditulis ulang sehingga Anda dapat membagikannya.sumber
--onto newroot
pilihan adalah berlebihan; Anda dapat melakukannya tanpanya karena argumen yang Anda berikan,,newroot
sama dengan argumen hulu -newroot
.git-checkout
beralih itu. Saya telah memperbaruinya dengan menyebutkan pendekatan itu terlebih dahulu, terima kasih atas penunjuknya.git rebase --merge -s recursive -X theirs --onto newroot --root master
untuk menyelesaikan semua konflik secara otomatis (lihat jawaban ini ). @AlexanderKuzinGabungan jawaban Aristoteles Pagaltzis dan Uwe Kleine-König dan komentar Richard Bronosky.
(hanya untuk meletakkan semuanya di satu tempat)
sumber
git rebase newroot master
, karena kesalahan.Saya suka jawaban Aristoteles. Tetapi menemukan bahwa untuk repositori besar (> 5000 commit), filter-branch bekerja lebih baik daripada rebase karena beberapa alasan 1) lebih cepat 2) tidak memerlukan intervensi manusia ketika ada konflik gabungan. 3) itu dapat menulis ulang tag - melestarikannya. Perhatikan bahwa cabang-filter berfungsi karena tidak ada pertanyaan tentang konten dari setiap komit - itu persis sama dengan sebelum 'rebase' ini.
Langkah saya adalah:
Perhatikan bahwa opsi '--tag-name-filter cat' berarti bahwa tag akan ditulis ulang untuk menunjukkan komit yang baru dibuat.
sumber
Saya menggunakan potongan jawaban Aristoteles dan Kent dengan sukses:
Ini juga akan menulis ulang semua cabang (bukan hanya
master
) di samping tag.sumber
refs/original/
dan menghapus setiap referensi. Wasit yang dihapus seharusnya sudah direferensikan oleh beberapa cabang lain, sehingga mereka tidak benar-benar pergi, hanyarefs/original/
akan dihapus.timedatectl set-time '2017-01-01 00:00:00'
memberinewroot
cap waktu lama.git rebase --root --onto $emptyrootcommit
harus melakukan trik dengan mudah
sumber
$emptyrootcommit
adalah variabel shell yang mengembang ke apa-apa, tentunya?Saya pikir menggunakan
git replace
dangit filter-branch
merupakan solusi yang lebih baik daripada menggunakangit rebase
:Ide di baliknya adalah untuk:
git filter-branch
Berikut ini skrip untuk 2 langkah pertama:
Anda dapat menjalankan skrip ini tanpa risiko (bahkan jika melakukan pencadangan sebelum melakukan tindakan yang tidak pernah Anda lakukan sebelumnya adalah ide yang baik;)), dan jika hasilnya tidak sesuai harapan, hapus saja file yang dibuat dalam folder
.git/refs/replace
dan coba lagi; )Setelah Anda memverifikasi bahwa keadaan repositori adalah yang Anda harapkan, jalankan perintah berikut untuk memperbarui sejarah semua cabang :
Sekarang, Anda harus melihat 2 sejarah, yang lama dan yang baru (lihat bantuan
filter-branch
untuk informasi lebih lanjut). Anda dapat membandingkan 2 dan memeriksa lagi apakah semuanya OK. Jika Anda puas, hapus file yang tidak diperlukan lagi:Anda bisa kembali ke
master
cabang Anda dan menghapus cabang sementara:Sekarang, semua harus dilakukan;)
sumber
Saya menjadi bersemangat dan menulis versi 'idempoten' dari skrip yang bagus ini ... itu akan selalu memasukkan komit kosong yang sama, dan jika Anda menjalankannya dua kali, itu tidak mengubah hash komit Anda setiap kali. Jadi, inilah pendapat saya tentang git-insert-empty-root :
Apakah sebanding dengan kompleksitas ekstra? mungkin tidak, tapi saya akan menggunakan yang ini.
HARUS ini juga memungkinkan untuk melakukan operasi ini pada beberapa salinan repo kloning, dan berakhir dengan hasil yang sama, sehingga mereka masih kompatibel ... menguji ... ya itu berhasil, berfungsi, tetapi perlu juga menghapus dan menambahkan Anda remote lagi, misalnya:
sumber
Untuk menambahkan komit kosong di awal repositori, jika Anda lupa membuat komit kosong segera setelah "git init":
sumber
Nah, inilah yang saya pikirkan:
sumber
Berikut
bash
skrip saya berdasarkan jawaban Kent dengan peningkatan:master
, ketika dilakukan;git checkout --orphan
hanya bekerja dengan cabang, bukan keadaan kepala terpisah, jadi itu diperiksa cukup lama untuk membuat root baru komit dan kemudian dihapus;filter-branch
(Kent meninggalkan pengganti di sana untuk penggantian manual);filter-branch
operasi penulisan ulang hanya cabang-cabang lokal, tidak remote terlalusumber
Untuk mengalihkan komit root:
Pertama, buat komit yang Anda inginkan sebagai yang pertama.
Kedua, alihkan urutan komit menggunakan:
git rebase -i --root
Editor akan muncul dengan komit sampai root melakukan, seperti:
pilih pesan lama 1234 root
pilih 0294 A komit di tengah
pilih 5678 komit yang ingin Anda masukkan ke root
Anda kemudian dapat menempatkan komit yang Anda inginkan terlebih dahulu, dengan menempatkannya di baris pertama. Dalam contoh:
pilih 5678 komit yang ingin Anda masukkan ke root
pilih pesan lama 1234 root
pilih 0294 A komit di tengah
Keluar dari editor, perintah komit akan berubah.
PS: Untuk mengubah penggunaan editor git, jalankan:
git config --global core.editor name_of_the_editor_program_you_want_to_use
sumber
Menggabungkan yang terbaru dan terhebat. Tidak ada efek samping, tidak ada konflik, menyimpan tag.
Perhatikan bahwa pada GitHub Anda akan kehilangan data CI run dan PR mungkin akan kacau kecuali cabang lain diperbaiki juga.
sumber
Mengikuti jawaban Aristoteles Pagaltzis dan lainnya tetapi menggunakan perintah yang lebih sederhana
Perhatikan bahwa repo Anda tidak boleh mengandung modifikasi lokal yang menunggu untuk dilakukan.
Note
git checkout --orphan
akan bekerja di git versi baru, kurasa.Catatan sebagian besar waktu
git status
memberikan petunjuk yang bermanfaat.sumber
Mulai repositori baru.
Atur kembali tanggal Anda ke tanggal mulai yang Anda inginkan.
Lakukan segala cara yang Anda inginkan Anda lakukan, sesuaikan waktu sistem untuk mencerminkan kapan Anda berharap Anda melakukannya dengan cara itu. Tarik file dari repositori yang ada sesuai kebutuhan untuk menghindari banyak pengetikan yang tidak perlu.
Ketika Anda sampai hari ini, tukar repositori dan Anda selesai.
Jika Anda hanya gila (mapan) tetapi cukup cerdas (mungkin, karena Anda harus memiliki sejumlah kecerdasan untuk memikirkan ide-ide gila seperti ini), Anda akan membuat skrip prosesnya.
Itu juga akan membuatnya lebih baik ketika Anda memutuskan Anda ingin masa lalu telah terjadi dengan cara lain seminggu dari sekarang.
sumber
Saya tahu posting ini sudah tua tetapi halaman ini adalah yang pertama ketika Googling "menyisipkan komit git".
Mengapa membuat hal-hal sederhana menjadi rumit?
Anda memiliki ABC dan Anda ingin ABZC.
git rebase -i trunk
(atau apapun sebelum B)git add ..
git commit
(git commit --amend
yang akan mengedit B dan tidak membuat Z)[Anda dapat menghasilkan sebanyak yang
git commit
Anda inginkan di sini untuk memasukkan lebih banyak komitmen. Tentu saja, Anda mungkin memiliki masalah dengan langkah 5, tetapi menyelesaikan konflik penggabungan dengan git adalah keterampilan yang harus Anda miliki. Jika tidak, berlatih!]git rebase --continue
Sederhana bukan?
Jika Anda mengerti
git rebase
, menambahkan komit 'root' seharusnya tidak menjadi masalah.Bersenang-senang dengan git!
sumber
git rebase
tidak dapat melakukan ini.