Saya baru saja membaca mengubah satu file di masa lalu komit di git tapi sayangnya solusi yang diterima 'menyusun ulang' komit, yang bukan yang saya inginkan. Jadi inilah pertanyaan saya:
Sesekali, saya melihat bug dalam kode saya saat mengerjakan fitur (tidak terkait). A quick git blame
kemudian mengungkapkan bahwa bug telah diperkenalkan beberapa komit yang lalu (saya melakukan cukup banyak, jadi biasanya itu bukan komit terbaru yang memperkenalkan bug). Pada titik ini, saya biasanya melakukan ini:
git stash # temporarily put my work aside
git rebase -i <bad_commit>~1 # rebase one step before the bad commit
# mark broken commit for editing
vim <affected_sources> # fix the bug
git add <affected_sources> # stage fixes
git commit -C <bad_commit> # commit fixes using same log message as before
git rebase --continue # base all later changes onto this
Namun, hal ini sering terjadi sehingga urutan di atas semakin mengganggu. Terutama 'rebase interaktif' yang membosankan. Apakah ada jalan pintas ke urutan di atas, yang memungkinkan saya mengubah komit arbitrer di masa lalu dengan perubahan bertahap? Saya sangat sadar bahwa ini mengubah sejarah, tetapi saya sering melakukan kesalahan sehingga saya sangat ingin memiliki sesuatu seperti itu
vim <affected_sources> # fix bug
git add -p <affected_sources> # Mark my 'fixup' hungs for staging
git fixup <bad_commit> # amend the specified commit with staged changes,
# rebase any successors of bad commit on rewritten
# commit.
Mungkin skrip cerdas yang dapat menulis ulang komitmen menggunakan alat pipa atau lebih?
rebase -i
?rebase --onto tmp bad-commit master
. Seperti yang tertulis, ini akan mencoba menerapkan komit buruk ke status komit tetap.Jawaban:
JAWABAN DIPERBARUI
Beberapa waktu yang lalu,
--fixup
argumen baru telah ditambahkangit commit
yang dapat digunakan untuk membuat komit dengan pesan log yang sesuaigit rebase --interactive --autosquash
. Jadi cara termudah untuk memperbaiki komit sebelumnya adalah sekarang:JAWABAN ASLI
Ini sedikit skrip Python yang saya tulis beberapa waktu lalu yang mengimplementasikan
git fixup
logika ini yang saya harapkan dalam pertanyaan awal saya. Skrip mengasumsikan bahwa Anda melakukan beberapa perubahan dan kemudian menerapkan perubahan tersebut ke komit yang diberikan.CATATAN : Skrip ini khusus untuk Windows; itu mencari
git.exe
dan menetapkanGIT_EDITOR
variabel lingkungan menggunakanset
. Sesuaikan ini sesuai kebutuhan untuk sistem operasi lain.Dengan menggunakan skrip ini saya dapat mengimplementasikan dengan tepat 'memperbaiki sumber yang rusak, perbaikan tahap, menjalankan alur kerja git fixup' yang saya minta:
sumber
git stash
dangit stash pop
sekitar rebase Anda untuk tidak lagi memerlukan direktori kerja yang bersihgit stash
dangit stash pop
: Anda benar sedang, tapi sayangnyagit stash
ini jauh lebih lambat pada Windows daripada di Linux atau OS / X. Karena direktori kerja saya biasanya bersih, saya menghilangkan langkah ini agar tidak memperlambat perintah.git rebase -i --fixup
, dan itu didasarkan kembali dari komitmen tetap sebagai titik awal, jadi argumen sha tidak diperlukan dalam kasus saya.git config --global rebase.autosquash true
Yang saya lakukan adalah:
Editor Anda akan terbuka dengan daftar 5 komit terakhir, siap untuk dicampuri. Perubahan:
...untuk:
Simpan & keluar dari editor Anda, dan perbaikan akan dipadatkan kembali ke komit miliknya.
Setelah Anda melakukannya beberapa kali, Anda akan melakukannya dalam beberapa detik dalam tidur Anda. Rebasing interaktif adalah fitur yang benar-benar menarik bagi saya di git. Ini sangat berguna untuk ini dan banyak lagi ...
sumber
--autosquash
sakelar untukgit rebase
, yang secara otomatis menyusun ulang langkah-langkah di editor untuk Anda. Lihat tanggapan saya untuk skrip yang memanfaatkan ini untuk mengimplementasikangit fixup
perintah.Agak terlambat ke pesta, tetapi berikut adalah solusi yang berfungsi seperti yang dibayangkan penulis.
Tambahkan ini ke .gitconfig Anda:
Contoh penggunaan:
Namun jika Anda memiliki perubahan yang tidak bertahap, Anda harus menyimpannya sebelum rebase.
Anda dapat mengubah alias menjadi simpanan secara otomatis, alih-alih memberikan peringatan. Namun, jika perbaikan tidak berlaku dengan bersih, Anda perlu membuka simpanan secara manual setelah memperbaiki konflik. Melakukan penyimpanan dan pemunculan secara manual tampaknya lebih konsisten dan tidak terlalu membingungkan.
sumber
git fixup HEAD
apa saya membuat alias. Saya juga bisa menggunakan amandemen untuk itu.amend = commit --amend --reuse-message=HEAD
Kemudian Anda cukup mengetikgit amend
ataugit amend -a
melewati editor untuk pesan komit.Untuk memperbaiki satu komit:
di mana a0b1c2d3 adalah komit yang ingin Anda perbaiki dan di mana 2 adalah jumlah komit +1 yang ditempelkan yang ingin Anda ubah.
Catatan: git rebase --autosquash tanpa -i tidak berfungsi tetapi dengan -i berfungsi, itu aneh.
sumber
--autosquash
tanpa-i
masih tidak berhasil.EDITOR=true git rebase --autosquash -i
PEMBARUAN: Versi skrip yang lebih bersih sekarang dapat ditemukan di sini: https://github.com/deiwin/git-dotfiles/blob/docs/bin/git-fixup .
Saya telah mencari sesuatu yang serupa. Skrip Python ini tampaknya terlalu rumit, oleh karena itu saya telah menyusun solusi saya sendiri:
Pertama, alias git saya terlihat seperti itu (dipinjam dari sini ):
Sekarang fungsi bash menjadi sangat sederhana:
Kode ini tahap pertama semua perubahan saat ini (Anda dapat menghapus bagian ini, jika Anda ingin membuat file sendiri). Kemudian buat perbaikan (squash juga dapat digunakan, jika itu yang Anda butuhkan) komit. Setelah itu ia memulai rebase interaktif dengan
--autosquash
flag pada induk komit yang Anda berikan sebagai argumen. Itu akan membuka editor teks yang dikonfigurasi, sehingga Anda dapat memverifikasi bahwa semuanya seperti yang Anda harapkan dan cukup menutup editor akan menyelesaikan prosesnya.Bagian
if [[ "$1" == HEAD* ]]
(dipinjam dari sini ) digunakan, karena jika Anda menggunakan, misalnya, HEAD ~ 2 sebagai referensi komit Anda (komit yang ingin Anda perbaiki perubahan saat ini dengan) referensi maka HEAD akan dipindahkan setelah komit perbaikan dibuat dan Anda perlu menggunakan HEAD ~ 3 untuk merujuk ke komit yang sama.sumber
Anda dapat menghindari tahapan interaktif dengan menggunakan editor "null":
Ini akan digunakan
/bin/true
sebagai editor, bukan/usr/bin/vim
. Itu selalu menerima apa pun yang disarankan git, tanpa disuruh.sumber
call(["set", "GIT_EDITOR=true", "&&", git, "rebase", "-i" ...
).Yang benar-benar mengganggu saya tentang alur kerja perbaikan adalah bahwa saya harus memikirkan sendiri komitmen mana yang ingin saya ubah setiap saat. Saya membuat perintah "git fixup" yang membantu dalam hal ini.
Perintah ini membuat perbaikan komit, dengan keajaiban tambahan yang menggunakan git-deps untuk secara otomatis menemukan komit yang relevan, sehingga alur kerja sering kali turun ke:
Ini hanya bekerja jika perubahan bertahap dapat dikaitkan dengan jelas ke komit tertentu pada pohon kerja (antara master dan HEAD). Saya menemukan bahwa kasus ini sangat sering terjadi untuk jenis perubahan kecil yang saya gunakan untuk ini, misalnya kesalahan ketik pada komentar atau nama metode yang baru diperkenalkan (atau diganti namanya). Jika tidak demikian, setidaknya daftar calon komit akan ditampilkan.
Saya menggunakan ini banyak di alur kerja saya sehari-hari, untuk segera mengintegrasikan perubahan kecil ke baris sebelumnya berubah menjadi komit pada cabang kerja saya. Naskahnya tidak seindah yang seharusnya, dan ditulis dalam zsh, tetapi telah melakukan pekerjaan yang cukup baik untuk saya selama beberapa waktu sekarang sehingga saya tidak pernah merasa perlu untuk menulis ulang:
https://github.com/Valodim/git-fixup
sumber
Anda dapat membuat perbaikan untuk file tertentu dengan menggunakan alias ini.
Jika Anda telah membuat beberapa perubahan
myfile.txt
tetapi Anda tidak ingin memasukkannya ke dalam komit baru,git fixup-file myfile.txt
akan membuatfixup!
untuk komit di manamyfile.txt
terakhir kali diubah, dan kemudian akanrebase --autosquash
.sumber
git rebase
tidak dipanggil secara otomatis.commit --fixup
danrebase --autosquash
hebat, tetapi tidak cukup. Ketika saya memiliki urutan komitA-B-C
dan saya menulis beberapa perubahan lagi di pohon kerja saya yang termasuk dalam satu atau beberapa komit yang ada, saya harus melihat riwayat secara manual, memutuskan perubahan mana yang termasuk dalam komit mana, menetapkannya dan membuatfixup!
melakukan. Tetapi git sudah memiliki akses ke informasi yang cukup untuk dapat melakukan semua itu untuk saya, jadi saya telah menulis skrip Perl yang melakukan hal itu.Untuk setiap
git diff
bagian dalam skrip digunakangit blame
untuk menemukan komit yang terakhir menyentuh baris yang relevan, dan panggilangit commit --fixup
untuk menulisfixup!
komit yang sesuai , pada dasarnya melakukan hal yang sama yang saya lakukan secara manual sebelumnya.Jika Anda merasa berguna, silakan perbaiki dan ulangi dan mungkin suatu hari kami akan mendapatkan fitur seperti itu dengan
git
benar. Saya ingin melihat alat yang dapat memahami bagaimana konflik penggabungan harus diselesaikan ketika telah diperkenalkan oleh rebase interaktif.sumber
Saya menulis fungsi shell kecil yang dipanggil
gcf
untuk melakukan perbaikan perbaikan dan rebase secara otomatis:Misalnya, Anda dapat menambal komit kedua sebelum yang terbaru dengan:
gcf HEAD~~
Ini fungsinya . Anda dapat menempelkannya ke file
~/.bashrc
Ini digunakan
--autostash
untuk menyimpan dan memunculkan setiap perubahan yang tidak mengikat jika perlu.--autosquash
membutuhkan--interactive
rebase, tapi kami menghindari interaksi dengan menggunakan dummyEDITOR
.--no-fork-point
melindungi komit agar tidak dijatuhkan secara diam-diam dalam situasi yang jarang terjadi (saat Anda telah bercabang di cabang baru, dan seseorang telah melakukan rebased pada komitmen sebelumnya).sumber
Saya tidak mengetahui cara otomatis, tetapi berikut adalah solusi yang mungkin dengan lebih mudah melakukan bot manusia:
sumber
git fixup
perintah.--autosquash
Saya akan merekomendasikan https://github.com/tummychow/git-absorb :
sumber