Saya tidak sengaja melakukan file yang tidak diinginkan ( filename.orig
saat menyelesaikan penggabungan) ke repositori saya beberapa komit yang lalu, tanpa saya sadari sampai sekarang. Saya ingin sepenuhnya menghapus file dari riwayat repositori.
Apakah mungkin untuk menulis ulang sejarah perubahan sedemikian rupa sehingga filename.orig
tidak pernah ditambahkan ke repositori?
git
git-filter-branch
git-rewrite-history
git-rm
Grant Limberg
sumber
sumber
Jawaban:
Tolong jangan gunakan resep ini jika situasi Anda tidak seperti yang dijelaskan dalam pertanyaan. Resep ini untuk memperbaiki gabungan yang buruk, dan memutar ulang komitmen baik Anda ke gabungan tetap.
Meskipun
filter-branch
akan melakukan apa yang Anda inginkan, ini adalah perintah yang cukup kompleks dan saya mungkin akan memilih untuk melakukan inigit rebase
. Itu mungkin preferensi pribadi.filter-branch
dapat melakukannya dalam satu perintah, sedikit lebih kompleks, sedangkanrebase
solusinya melakukan operasi logis yang setara satu langkah pada satu waktu.Coba resep berikut ini:
(Perhatikan bahwa Anda sebenarnya tidak memerlukan cabang sementara, Anda bisa melakukan ini dengan 'HEAD terpisah', tetapi Anda perlu mencatat id komit yang dihasilkan oleh
git commit --amend
langkah untuk memasok kegit rebase
perintah daripada menggunakan cabang sementara nama.)sumber
git rebase -i
lebih cepat dan masih mudah? $ git rebase -i <sh1-of-merge> Tandai yang benar sebagai "edit" $ git rm somefile.orig $ git komit - ubah $ git rebase - lanjutkan Namun untuk beberapa alasan saya masih memiliki file itu di suatu tempat yang terakhir waktu saya melakukan itu. Mungkin melewatkan sesuatu.git rebase -i
sangat berguna, terutama ketika Anda memiliki beberapa operasi rebase-y untuk dilakukan, tetapi itu adalah rasa sakit yang tepat untuk menggambarkan secara akurat ketika Anda tidak benar-benar menunjuk ke bahu seseorang dan dapat melihat apa yang mereka lakukan dengan editor mereka. Saya menggunakan vim, tetapi tidak semua orang akan senang dengan: "ggjcesquash <Esc> jddjp: wq" dan instruksi seperti "Pindahkan baris teratas ke setelah baris kedua saat ini dan ubah kata pertama pada baris empat menjadi 'edit' sekarang simpan dan berhenti "dengan cepat tampak lebih rumit daripada langkah sebenarnya. Anda biasanya berakhir dengan beberapa--amend
dan--continue
tindakan, juga.Intro: Anda Memiliki 5 Solusi
Poster asli menyatakan:
Ada banyak cara berbeda untuk menghapus riwayat file sepenuhnya dari git:
Dalam hal poster asli, mengubah komit sebenarnya bukan pilihan dengan sendirinya, karena dia membuat beberapa komitmen tambahan setelahnya, tetapi demi kelengkapan, saya juga akan menjelaskan bagaimana melakukannya, untuk siapa pun yang hanya ingin untuk mengubah komit mereka sebelumnya.
Perhatikan bahwa semua solusi ini melibatkan mengubah / menulis ulang riwayat / komit dengan satu cara lain, sehingga siapa pun yang memiliki salinan komit lama harus melakukan pekerjaan ekstra untuk menyinkronkan kembali sejarah mereka dengan riwayat baru.
Solusi 1: Mengubah Komitmen
Jika Anda secara tidak sengaja membuat perubahan (seperti menambahkan file) di komit sebelumnya, dan Anda tidak ingin riwayat perubahan itu ada lagi, maka Anda dapat mengubah komit sebelumnya untuk menghapus file dari itu:
Solusi 2: Hard Reset (Kemungkinan Plus Rebase)
Seperti solusi # 1, jika Anda hanya ingin menghilangkan komit Anda sebelumnya, maka Anda juga memiliki opsi untuk melakukan hard reset ke induknya:
Perintah tersebut akan sulit-ulang cabang Anda dengan sebelumnya 1 st orangtua komit.
Namun , jika, seperti poster asli, Anda telah membuat beberapa komit setelah komit yang ingin Anda batalkan perubahannya, Anda masih dapat menggunakan pengaturan ulang yang keras untuk memodifikasinya, tetapi melakukannya juga melibatkan penggunaan rebase. Berikut adalah langkah-langkah yang dapat Anda gunakan untuk mengubah komitmen lebih lanjut dalam sejarah:
Solusi 3: Rebase Non-interaktif
Ini akan berfungsi jika Anda hanya ingin menghapus seluruh komit dari riwayat:
Solusi 4: Rebases Interaktif
Solusi ini akan memungkinkan Anda untuk mencapai hal-hal yang sama seperti solusi # 2 dan # 3, yaitu memodifikasi atau menghapus commit lebih lanjut dalam sejarah daripada komit Anda sebelumnya, sehingga solusi yang Anda pilih untuk digunakan adalah terserah Anda. Rebases interaktif tidak cocok untuk rebending ratusan komit, karena alasan kinerja, jadi saya akan menggunakan rebases non-interaktif atau solusi cabang filter (lihat di bawah) dalam situasi semacam itu.
Untuk memulai rebase interaktif, gunakan yang berikut:
Ini akan menyebabkan git untuk memundurkan kembali komit ke induk dari komit yang ingin Anda modifikasi atau hapus. Ini kemudian akan memberi Anda daftar komitmen rewound dalam urutan terbalik dalam editor git apa pun yang ditetapkan untuk digunakan (ini adalah Vim secara default):
Komit yang ingin Anda modifikasi atau hapus akan berada di bagian atas daftar ini. Untuk menghapusnya, cukup hapus barisnya dalam daftar. Jika tidak, ganti "memilih" dengan "edit" pada 1 st line, seperti begitu:
Selanjutnya, masuk
git rebase --continue
. Jika Anda memilih untuk menghapus komit sepenuhnya, maka hanya itu yang perlu Anda lakukan (selain verifikasi, lihat langkah terakhir untuk solusi ini). Jika, di sisi lain, Anda ingin memodifikasi komit, maka git akan menerapkan kembali komit dan kemudian menjeda rebase.Pada titik ini, Anda dapat menghapus file dan mengubah komit, kemudian melanjutkan rebase:
Itu dia. Sebagai langkah terakhir, apakah Anda memodifikasi komit atau menghapusnya sepenuhnya, itu ide yang baik untuk memverifikasi bahwa tidak ada perubahan tak terduga lainnya yang dilakukan pada cabang Anda dengan membedakannya dengan statusnya sebelum rebase:
Solusi 5: Memfilter Cabang
Akhirnya, solusi ini yang terbaik jika Anda ingin menghapus semua jejak keberadaan file dari sejarah, dan tidak ada solusi lain yang cukup untuk tugas itu.
Itu akan menghapus
<file>
dari semua komit, mulai dari komit root. Jika sebaliknya Anda hanya ingin menulis ulang rentang komitHEAD~5..HEAD
, maka Anda bisa meneruskannya sebagai argumen tambahanfilter-branch
, seperti yang ditunjukkan dalam jawaban ini :Sekali lagi, setelah
filter-branch
selesai, biasanya ide yang baik untuk memverifikasi bahwa tidak ada perubahan tak terduga lainnya dengan membedakan cabang Anda dengan keadaan sebelumnya sebelum operasi penyaringan:Alternatif Filter-Cabang: BFG Repo Cleaner
Saya pernah mendengar bahwa alat Repo Cleaner BFG berjalan lebih cepat daripada
git filter-branch
, jadi Anda mungkin ingin memeriksanya sebagai opsi juga. Bahkan disebutkan secara resmi dalam dokumentasi cabang-filter sebagai alternatif yang layak:Sumber daya tambahan
sumber
filter-branch
menyebabkan penghitungan ulang hash? Jika sebuah tim bekerja dengan repo di mana file besar harus disaring, bagaimana mereka melakukan ini sehingga semua orang berakhir dengan keadaan repo yang sama?Jika Anda belum melakukan apa pun sejak itu, cukup
git rm
file dangit commit --amend
.Jika Anda memiliki
akan melalui setiap perubahan dari
merge-point
menjadiHEAD
, menghapus nama file.orig dan menulis ulang perubahan. Menggunakan--ignore-unmatch
berarti perintah tidak akan gagal jika karena alasan filename.orig hilang dari perubahan. Itulah cara yang disarankan dari bagian Contoh di halaman manual git-filter-branch .Catatan untuk pengguna Windows: Jalur file harus menggunakan garis miring
sumber
git-filter-branch
sepertinya memberi yang pertama.filter-branch
"
dan tidak'
saat menggunakan Windows, atau Anda akan mendapatkan kesalahan "revisi buruk" yang tidak membantu.Ini adalah cara terbaik:
http://github.com/guides/completely-remove-a-file-from-all-revisions
Pastikan untuk membuat cadangan salinan file terlebih dahulu.
EDIT
Hasil edit oleh Neon sayangnya ditolak saat ditinjau.
Lihat Neons pos di bawah ini, mungkin berisi informasi yang berguna!
Misalnya untuk menghapus semua
*.gz
file yang secara tidak sengaja dilakukan ke repositori git:Itu masih tidak berhasil untuk saya? (Saya saat ini di git versi 1.7.6.1)
Tidak yakin mengapa, karena saya hanya punya SATU cabang master. Bagaimanapun, saya akhirnya mendapatkan repositori git saya benar-benar dibersihkan dengan mendorong ke repositori kosong dan kosong git baru, misalnya
(Iya!)
Lalu saya mengkloning itu ke direktori baru dan pindah ke folder .git ke yang ini. misalnya
(Ya! Akhirnya dibersihkan!)
Setelah memverifikasi bahwa semuanya baik-baik saja, maka Anda dapat menghapus
../large_dot_git
dan../tmpdir
direktori (mungkin dalam beberapa minggu atau bulan dari sekarang, untuk berjaga-jaga ...)sumber
--prune-empty
untuk menambahkan ke perintah filter-branch.Menulis ulang sejarah Git menuntut perubahan semua id komit yang terkena dampak, sehingga setiap orang yang mengerjakan proyek perlu menghapus salinan lama repo mereka, dan melakukan klon baru setelah Anda membersihkan histori. Semakin banyak orang yang mengalami ketidaknyamanan, semakin Anda membutuhkan alasan yang baik untuk melakukannya - file berlebihan Anda tidak benar-benar menyebabkan masalah, tetapi jika hanya Anda yang mengerjakan proyek, Anda mungkin juga membersihkan sejarah Git jika Anda mau untuk!
Untuk membuatnya semudah mungkin, saya sarankan menggunakan BFG Repo-Cleaner , alternatif yang lebih sederhana dan lebih cepat untuk
git-filter-branch
secara khusus dirancang untuk menghapus file dari sejarah Git. Salah satu cara yang membuat hidup Anda lebih mudah di sini adalah bahwa itu sebenarnya menangani semua referensi secara default (semua tag, cabang, dll) tetapi juga 10 - 50x lebih cepat.Anda harus hati-hati mengikuti langkah-langkah di sini: http://rtyley.github.com/bfg-repo-cleaner/#usage - tetapi inti intinya adalah ini: unduh toples BFG (memerlukan Java 6 atau lebih tinggi) dan jalankan perintah ini :
Seluruh riwayat repositori Anda akan dipindai, dan setiap file bernama
filename.orig
(yang tidak ada dalam komit terbaru Anda ) akan dihapus. Ini jauh lebih mudah daripada menggunakangit-filter-branch
untuk melakukan hal yang sama!Pengungkapan penuh: Saya penulis Repo-Cleaner BFG.
sumber
sumber
Hanya untuk menambahkan itu ke solusi Charles Bailey, saya hanya menggunakan git rebase -i untuk menghapus file yang tidak diinginkan dari komit sebelumnya dan itu bekerja seperti pesona. Langkah langkah:
sumber
Cara paling sederhana yang saya temukan disarankan oleh
leontalbot
(sebagai komentar), yang merupakan posting yang diterbitkan oleh Anoopjohn . Saya pikir nilainya ruang sendiri sebagai jawaban:(Saya mengonversinya menjadi skrip bash)
Semua kredit ditujukan untuk
Annopjohn
, danleontalbot
untuk menunjukkannya.CATATAN
Ketahuilah bahwa skrip tidak menyertakan validasi, jadi pastikan Anda tidak membuat kesalahan dan bahwa Anda memiliki cadangan jika terjadi kesalahan. Itu bekerja untuk saya, tetapi mungkin tidak berhasil dalam situasi Anda. GUNAKAN DENGAN AWAS (ikuti tautan jika Anda ingin tahu apa yang sedang terjadi).
sumber
Jelas,
git filter-branch
ini jalan yang harus ditempuh.Sayangnya, ini tidak akan cukup untuk sepenuhnya menghapus
filename.orig
dari repo Anda, karena masih dapat dirujuk oleh tag, entri reflog, remote dan sebagainya.Saya sarankan menghapus semua referensi ini juga, dan kemudian memanggil pengumpul sampah. Anda dapat menggunakan
git forget-blob
skrip dari situs web ini untuk melakukan semua ini dalam satu langkah.git forget-blob filename.orig
sumber
Jika ini adalah komit terbaru yang ingin Anda bersihkan, saya mencoba dengan git versi 2.14.3 (Apple Git-98):
sumber
git reflog expire --expire=now --all; git gc --prune=now
adalah hal yang sangat buruk untuk dilakukan. Kecuali Anda kehabisan ruang disk, biarkan sampah git mengumpulkan komitmen ini setelah beberapa mingguInilah yang
git filter-branch
dirancang untuk.sumber
Anda juga bisa menggunakan:
git reset HEAD file/path
sumber