Saya biasanya mengirimkan daftar komitmen untuk ditinjau. Jika saya memiliki komitmen berikut:
HEAD
Commit3
Commit2
Commit1
... Saya tahu bahwa saya dapat memodifikasi head commit git commit --amend
. Tetapi bagaimana saya bisa memodifikasi Commit1
, mengingat itu bukan HEAD
komit?
git
git-rewrite-history
Sam Liao
sumber
sumber
Jawaban:
Anda dapat menggunakan git rebase . Misalnya, jika Anda ingin memodifikasi komit
bbc643cd
, jalankanHarap perhatikan tanda sisipan
^
di akhir perintah, karena Anda harus benar-benar mengubah kembali ke komit sebelum yang Anda ingin modifikasi .Di editor default, ubah
pick
keedit
dalam baris yang menyebutkan 'bbc643cd'.Simpan file dan keluar: git akan menafsirkan dan secara otomatis menjalankan perintah dalam file. Anda akan menemukan diri Anda dalam situasi sebelumnya di mana Anda baru saja membuat komit
bbc643cd
.Pada titik ini,
bbc643cd
adalah komit terakhir Anda dan Anda dapat dengan mudah mengubahnya : lakukan perubahan lalu komit dengan perintah:Setelah itu, ketikkan:
untuk kembali ke komit HEAD sebelumnya.
PERINGATAN : Perhatikan bahwa ini akan mengubah SHA-1 dari komit itu dan juga semua anak - dengan kata lain, ini menulis ulang sejarah dari titik itu ke depan. Anda dapat memecahkan repo melakukan ini jika Anda menekan menggunakan perintah
git push --force
sumber
reword
tindakangit rebase -i
sebagai gantinyaedit
(itu secara otomatis membuka editor dan melanjutkan dengan langkah-langkah rebase lainnya; ini meniadakan penggunaangit commit --ammend
dangit rebase --continue
ketika Anda hanya perlu mengubah pesan komit dan bukan konten. ).git stash
sebelumgit rebase
dangit stash pop
sesudahnya, jika Anda memiliki perubahan yang tertunda.git commit --all --amend --no-edit
sini. Yang harus saya lakukan setelahgit rebase -i ...
itu adalahgit commit --amend
biasanyagit rebase --continue
.Gunakan rebase interaktif yang luar biasa:
Temukan komit yang Anda inginkan, ubah
pick
kee
(edit
), dan simpan dan tutup file. Git akan mundur ke komitmen itu, memungkinkan Anda untuk:git commit --amend
untuk membuat perubahan, ataugit reset @~
untuk membuang komit terakhir, tetapi bukan perubahan pada file (yaitu membawa Anda ke titik di mana Anda sudah mengedit file, tetapi belum berkomitmen).Yang terakhir berguna untuk melakukan hal-hal yang lebih kompleks seperti membelah menjadi beberapa komit.
Kemudian, jalankan
git rebase --continue
, dan Git akan memutar ulang perubahan berikutnya di atas komit Anda yang dimodifikasi. Anda mungkin diminta untuk memperbaiki beberapa konflik penggabungan.Catatan:
@
adalah singkatan untukHEAD
, dan~
merupakan komit sebelum komit yang ditentukan.Baca lebih lanjut tentang penulisan ulang riwayat di dokumen Git.
Jangan takut untuk rebase
ProTip ™: Jangan takut untuk bereksperimen dengan perintah "berbahaya" yang menulis ulang riwayat * - Git tidak menghapus komit Anda selama 90 hari secara default; Anda dapat menemukannya di reflog:
* Hati-hati dengan opsi seperti
--hard
dan--force
meskipun - mereka dapat membuang data.* Juga, jangan menulis ulang sejarah di cabang mana pun Anda berkolaborasi.
Pada banyak sistem,
git rebase -i
secara default akan membuka Vim. Vim tidak berfungsi seperti kebanyakan editor teks modern, jadi lihatlah cara rebase menggunakan Vim . Jika Anda lebih suka menggunakan editor yang berbeda, ubahlah dengangit config --global core.editor your-favorite-text-editor
.sumber
@
sebagai singkatanHEAD
. Terima kasih telah memposting ini.git reset @~
persis apa yang ingin saya lakukan setelah memilih komit dengangit rebase ...
. Anda adalah pahlawan saya)Rebase interaktif dengan
--autosquash
sesuatu yang sering saya gunakan ketika saya harus memperbaiki komitmen sebelumnya lebih dalam dalam sejarah. Ini pada dasarnya mempercepat proses yang diilustrasikan jawaban ZelluX, dan sangat berguna ketika Anda memiliki lebih dari satu komit yang perlu Anda edit.Dari dokumentasi:
Asumsikan Anda memiliki riwayat yang terlihat seperti ini:
dan Anda memiliki perubahan yang ingin Anda ubah menjadi Commit2 lalu komit perubahan Anda menggunakan
Sebagai alternatif, Anda dapat menggunakan komit-sha alih-alih pesan komit, jadi
"fixup! e8adec4
atau bahkan hanya awalan dari pesan komit.Kemudian lakukan rebase interaktif pada komit sebelumnya
editor Anda akan terbuka dengan komit yang sudah dipesan dengan benar
yang perlu Anda lakukan hanyalah menyimpan dan keluar
sumber
git commit --fixup=@~
bukangit commit -m "fixup! Commit2"
. Ini sangat berguna ketika pesan komit Anda lebih panjang dan akan sulit untuk mengetik semuanya.Lari:
$ git rebase --interactive commit_hash^
masing-masing
^
menunjukkan berapa banyak komit yang ingin Anda edit, jika hanya satu (hash komit yang Anda tentukan), maka Anda tinggal menambahkan satu^
.Menggunakan Vim Anda mengubah kata-kata
pick
untukreword
untuk komit Anda ingin perubahan, save dan keluar (:wq
). Kemudian git akan meminta Anda dengan setiap komit yang Anda tandai sebagai reword sehingga Anda dapat mengubah pesan komit.Setiap pesan komit, Anda harus menyimpan dan keluar (
:wq
) untuk pergi ke pesan komit berikutnyaJika Anda ingin keluar tanpa menerapkan perubahan, tekan
:q!
EDIT : untuk menavigasi yang
vim
Anda gunakanj
untuk naik,k
turun,h
ke kiri, danl
ke kanan (semua ini dalamNORMAL
mode, tekanESC
untuk pergi keNORMAL
mode). Untuk mengedit teks, tekani
agar Anda masuk keINSERT
mode, tempat Anda memasukkan teks. TekanESC
untuk kembali keNORMAL
mode :)UPDATE : Berikut adalah tautan bagus dari daftar github Cara membatalkan (hampir) apa pun dengan git
sumber
git push --force
?git push --force
dilakukan adalah menimpa komit remote dengan komit lokal Anda. Itu bukan kasus topik ini :)Jika karena alasan tertentu Anda tidak menyukai editor interaktif, Anda dapat menggunakannya
git rebase --onto
.Katakanlah Anda ingin memodifikasi
Commit1
. Pertama, cabang dari sebelumnyaCommit1
:Kedua, ambil
Commit1
dengancherry-pick
:Sekarang, ubah perubahan Anda, buat
Commit1'
:Dan akhirnya, setelah menyembunyikan perubahan lain, transplantasi sisa komitmen Anda hingga
master
di atas komitmen baru Anda:Baca: "rebase, ke cabang
amending
, semua komit antaraCommit1
(tidak inklusif) danmaster
(inklusif)". Yaitu, Commit2 dan Commit3, memotong Commit1 lama sepenuhnya. Anda bisa saja memetiknya, tetapi cara ini lebih mudah.Ingatlah untuk membersihkan cabang Anda!
sumber
git checkout -b amending Commit1~1
untuk mendapatkan komit sebelumnyagit checkout -b amending Commit1
?Berdasarkan Dokumentasi
Mengubah pesan dari pesan komit yang lebih tua atau banyak
Di atas menampilkan daftar 3 commit terakhir pada cabang saat ini, ubah 3 ke yang lain jika Anda menginginkan lebih. Daftar ini akan terlihat mirip dengan yang berikut:
Ganti pick dengan reword sebelum setiap pesan komit yang ingin Anda ubah. Katakanlah Anda mengubah komit kedua dalam daftar, file Anda akan terlihat seperti berikut:
Simpan dan tutup file komit, ini akan memunculkan editor baru bagi Anda untuk mengubah pesan komit Anda, mengubah pesan komit dan menyimpan.
Finaly Angkatan-dorong komitmen diubah.
sumber
Perintah yang sepenuhnya non-interaktif (1)
Saya hanya berpikir saya akan membagikan alias yang saya gunakan untuk ini. Ini didasarkan pada rebase interaktif non-interaktif . Untuk menambahkannya ke git Anda, jalankan perintah ini (penjelasan diberikan di bawah):
Keuntungan terbesar dari perintah ini adalah kenyataan bahwa itu tidak ada-vim .
(1) mengingat bahwa tidak ada konflik selama rebase, tentu saja
Pemakaian
Nama itu
amend-to
tampaknya sesuai IMHO. Bandingkan arus dengan--amend
:Penjelasan
git config --global alias.<NAME> '!<COMMAND>'
- Membuat alias global git bernama<NAME>
yang akan menjalankan perintah non-git<COMMAND>
f() { <BODY> }; f
- fungsi bash "anonim".SHA=`git rev-parse "$1"`;
- Mengonversi argumen menjadi revisi git, dan memberikan hasilnya ke variabelSHA
git commit --fixup "$SHA"
- fixup-commit untukSHA
. Lihatgit-commit
dokumenGIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^"
git rebase --interactive "$SHA^"
sebagian telah dicakup oleh jawaban lain.--autosquash
adalah apa yang digunakan bersamaan dengangit commit --fixup
, lihatgit-rebase
dokumen untuk info lebih lanjutGIT_SEQUENCE_EDITOR=true
adalah apa yang membuat semuanya menjadi non-interaktif. Peretasan ini saya pelajari dari posting blog ini .sumber
amend-to
menangani file yang tidak dipentaskan:git config --global alias.amend-to '!f() { SHA=
git rev-parse "$ 1"; git stash -k && git commit --fixup "$SHA" && GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^" && git stash pop; }; f'
Sunting rebase interaktif otomatis diikuti dengan komit kembalikan yang siap untuk dilakukan
Saya menemukan diri saya cukup sering melakukan commit di masa lalu sehingga saya menulis skrip untuk itu.
Inilah alur kerjanya:
Ini akan menjatuhkan Anda pada komit yang ingin Anda edit.
Perbaiki dan tampilkan komit sesuai keinginan Anda.
(Anda mungkin ingin menggunakan
git stash save
untuk menyimpan file yang tidak Anda lakukan)Ulangi komit dengan
--amend
, misalnya:Lengkapi rebase:
Agar cara di atas berfungsi, masukkan skrip di bawah ini ke dalam file yang dapat dieksekusi yang dipanggil
git-commit-edit
di suatu tempat di$PATH
:sumber
Datang ke pendekatan ini (dan mungkin persis sama dengan menggunakan rebase interaktif) tetapi bagi saya itu agak mudah.
Catatan: Saya menyajikan pendekatan ini demi ilustrasi apa yang dapat Anda lakukan daripada alternatif sehari-hari. Karena memiliki banyak langkah (dan mungkin beberapa peringatan.)
Katakanlah Anda ingin mengubah komit
0
dan Anda sedang aktiffeature-branch
Periksa komitmen ini dan buat a
quick-branch
. Anda juga dapat mengkloning cabang fitur Anda sebagai titik pemulihan (sebelum memulai).Anda sekarang akan memiliki sesuatu seperti ini:
Panggung berubah, sembunyikan yang lainnya.
Lakukan perubahan dan checkout kembali ke
feature-branch
Anda sekarang akan memiliki sesuatu seperti ini:
Rebase
feature-branch
kequick-branch
(menyelesaikan konflik di sepanjang jalan). Terapkan simpanan dan hapusquick-branch
.Dan Anda berakhir dengan:
Git tidak akan menggandakan (walaupun saya tidak bisa mengatakan sampai sejauh mana) 0 komit ketika rebasing.
Catatan: semua hash komit diubah mulai dari komit yang semula ingin kami ubah.
sumber
Untuk mendapatkan perintah non-interaktif, letakkan skrip dengan konten ini di PATH Anda:
Gunakan dengan mengatur perubahan Anda (dengan
git add
) dan kemudian jalankangit fixup <commit-to-modify>
. Tentu saja, itu akan tetap interaktif jika Anda mendapat konflik.sumber
git stash
+rebase
otomatisasiKetika saya perlu memodifikasi komit lama berkali-kali untuk ulasan Gerrit, saya sudah melakukan:
GitHub hulu .
Pemakaian:
git add
jika sudah di repogit-amend-old $old_sha
Saya suka ini
--autosquash
karena tidak menghancurkan perbaikan yang tidak terkait lainnya.sumber
git amend
untuk menerapkan perubahan pada komit tertentu dengan menggunakan simpanan saat ini, sangat pintar!Saya memecahkan ini,
1) dengan membuat komit baru dengan perubahan yang saya inginkan ..
2) saya tahu komit mana yang harus saya gabungkan. yaitu komit 3.
jadi,
git rebase -i HEAD~4
# 4 mewakili komit terbaru (di sini komit 3 ada di posisi ke-4)3) dalam rebase interaktif, komit terbaru akan terletak di bagian bawah. itu akan terlihat sama,
4) di sini kita perlu mengatur ulang komit jika Anda ingin bergabung dengan komit tertentu. seharusnya seperti,
setelah mengatur ulang Anda perlu mengganti
p
pick
denganf
( fixup akan bergabung tanpa pesan komit) ataus
( squash menggabungkan dengan pesan komit dapat berubah dalam waktu berjalan)dan kemudian simpan pohonmu.
sekarang bergabung dilakukan dengan komit yang ada.
sumber
Pilihan terbaik adalah menggunakan "perintah rebase interaktif" .
Sekarang bagaimana cara menggunakan perintah ini?
-i
berdiri untuk "interaktif" . Perhatikan bahwa Anda dapat melakukan rebase dalam mode non-interaktif. ex:HEAD
menunjukkan lokasi Anda saat ini (bisa juga nama cabang atau melakukan SHA). The~n
berarti "n beforeé, sehinggaHEAD~n
akan menjadi daftar 'n' komit sebelum yang Anda sedang.git rebase
memiliki perintah berbeda seperti:p
ataupick
untuk tetap berkomitmen seperti apa adanya.r
ataureword
: untuk menyimpan konten komit tetapi ubah pesan komit.s
atausquash
: untuk menggabungkan perubahan komit ini ke komit sebelumnya (komit di atasnya dalam daftar).... dll.
Catatan: Lebih baik membuat Git bekerja dengan editor kode Anda untuk membuatnya lebih sederhana. Seperti misalnya jika Anda menggunakan kode visual yang dapat Anda tambahkan seperti ini
git config --global core.editor "code --wait"
. Atau Anda dapat mencari di Google bagaimana menghubungkan Anda dengan editor kode yang Anda sukai dengan GIT.Contoh
git rebase
Saya ingin mengubah 2 komitmen terakhir yang saya lakukan sehingga saya memproses seperti ini:
Sekarang saya gunakan
git rebase
untuk mengubah 2 pesan komit terakhir:$git rebase -i HEAD~2
Ini membuka editor kode dan menunjukkan ini:Karena saya ingin mengubah pesan komit untuk 2 commit ini. Jadi saya akan mengetik
r
ataureword
menggantikanpick
. Kemudian Simpan file dan tutup tab. Catatan yangrebase
dieksekusi dalam proses multi-langkah sehingga langkah selanjutnya adalah memperbarui pesan. Perhatikan juga bahwa komit ditampilkan dalam urutan kronologis terbalik sehingga komit terakhir ditampilkan di komit tersebut dan komit pertama di baris pertama dan seterusnya.Perbarui pesan: Perbarui pesan pertama:
simpan dan tutup Edit pesan kedua
Simpan dan tutup.
Anda akan mendapatkan pesan seperti ini di akhir rebase:
Successfully rebased and updated refs/heads/documentation
yang berarti Anda berhasil. Anda dapat menampilkan perubahan:Saya berharap ini dapat membantu pengguna baru :).
sumber
Bagi saya itu untuk menghapus beberapa kredensial dari repo. Saya mencoba rebasing dan bertemu dengan banyak konflik yang tampaknya tidak berhubungan sepanjang jalan ketika mencoba untuk rebase - lanjutkan. Jangan repot-repot mencoba rebase sendiri, gunakan alat yang disebut BFG (brew install bfg) di mac.
sumber
Jika Anda belum mendorong komit maka Anda dapat kembali ke komit sebelumnya menggunakan
git reset HEAD^[1,2,3,4...]
Sebagai contoh
Ups, lupa menambahkan file2 ke komit pertama ...
Ini akan menambahkan file2 ke komit pertama.
sumber
Nah, solusi ini mungkin terdengar sangat konyol, tetapi dapat menyelamatkan Anda dalam kondisi tertentu.
Seorang teman saya secara tidak sengaja melakukan beberapa file besar (empat file yang dihasilkan secara otomatis, masing-masing berukuran antara 3GB hingga 5GB) dan kemudian membuat beberapa kode tambahan sebelum menyadari masalah yang
git push
tidak berfungsi lagi!File-file telah terdaftar
.gitignore
tetapi setelah mengganti nama folder kontainer, mereka terkena dan berkomitmen! Dan sekarang ada beberapa komitmen lebih dari kode di atas itu, tetapipush
berjalan selamanya (mencoba mengunggah data GB!) Dan akhirnya akan gagal karena batas ukuran file Github .Masalah dengan rebase interaktif atau yang serupa adalah bahwa mereka akan berurusan dengan mencari-cari file besar ini dan akan mengambil selamanya untuk melakukan apa pun. Namun demikian, setelah menghabiskan hampir satu jam di CLI, kami tidak yakin apakah file (dan delta) benar-benar dihapus dari sejarah atau tidak dimasukkan dalam komitmen saat ini. Dorongan itu tidak berhasil dan teman saya benar-benar macet.
Jadi, solusi yang saya temukan adalah:
~/Project-old
.~/Project
).cp -r
file dari~/Project-old
folder ke~/Project
.mv
ed, dan dimasukkan.gitignore
dengan benar..git
folder yang baru saja dikloning~/Project
oleh yang lama. Di situlah log sejarah yang bermasalah tinggal!push
diedit.Masalah terbesar dengan solusi ini adalah, ini berkaitan dengan menyalin beberapa file secara manual, dan juga menggabungkan semua commit terbaru menjadi satu (jelas dengan hash-commit baru.) B
Manfaat besar adalah, sangat jelas dalam setiap langkah, ini bekerja sangat baik untuk file besar (serta yang sensitif) , dan tidak meninggalkan jejak dalam sejarah!
sumber