Apa yang ingin Anda lakukan sangat mengganggu jika Anda telah menerbitkan riwayat ke pengembang lain. Lihat “Memulihkan Dari Hulu Rebase” dalam git rebase
dokumentasi untuk langkah-langkah yang diperlukan setelah memperbaiki riwayat Anda.
Anda memiliki setidaknya dua opsi: git filter-branch
dan rebase interaktif, keduanya dijelaskan di bawah ini.
Menggunakan git filter-branch
Saya memiliki masalah yang sama dengan data uji biner besar dari impor Subversion dan menulis tentang menghapus data dari repositori git .
Katakanlah sejarah git Anda adalah:
$ git lola --name-status
* f772d66 (HEAD, master) Login page
| A login.html
* cb14efd Remove DVD-rip
| D oops.iso
* ce36c98 Careless
| A oops.iso
| A other.html
* 5af4522 Admin page
| A admin.html
* e738b63 Index
A index.html
Perhatikan bahwa git lola
ini adalah alias yang tidak standar tetapi sangat bermanfaat. Dengan --name-status
sakelar, kita dapat melihat modifikasi hierarki yang terkait dengan setiap komit.
Dalam komit “Careless” (yang nama objek SHA1nya ce36c98) file tersebut oops.iso
adalah DVD-rip yang ditambahkan secara tidak sengaja dan dihapus di komit berikutnya, cb14efd. Menggunakan teknik yang dijelaskan dalam posting blog tersebut, perintah untuk mengeksekusi adalah:
git filter-branch --prune-empty -d /dev/shm/scratch \
--index-filter "git rm --cached -f --ignore-unmatch oops.iso" \
--tag-name-filter cat -- --all
Pilihan:
--prune-empty
menghapus komit yang menjadi kosong ( yaitu , jangan ubah susunan pohon) sebagai hasil dari operasi filter. Dalam kasus biasa, opsi ini menghasilkan riwayat yang lebih bersih.
-d
memberi nama direktori sementara yang belum ada untuk digunakan untuk membangun riwayat yang difilter. Jika Anda menjalankan distribusi Linux modern, menspesifikasikan sebuah pohon /dev/shm
akan menghasilkan eksekusi yang lebih cepat .
--index-filter
adalah acara utama dan berjalan melawan indeks pada setiap langkah dalam sejarah. Anda ingin menghapus di oops.iso
mana pun ditemukan, tetapi tidak ada di semua komit. Perintah git rm --cached -f --ignore-unmatch oops.iso
menghapus DVD-rip ketika ada dan tidak gagal sebaliknya.
--tag-name-filter
menjelaskan cara menulis ulang nama tag. Filter cat
adalah operasi identitas. Repositori Anda, seperti contoh di atas, mungkin tidak memiliki tag apa pun, tetapi saya menyertakan opsi ini untuk generalisasi penuh.
--
menentukan akhir opsi untuk git filter-branch
--all
berikut --
ini adalah singkatan untuk semua referensi. Repositori Anda, seperti contoh di atas, mungkin hanya memiliki satu ref (master), tetapi saya menyertakan opsi ini untuk generalisasi penuh.
Setelah beberapa berputar, sejarahnya sekarang:
$ git lola --name-status
* 8e0a11c (HEAD, master) Login page
| A login.html
* e45ac59 Careless
| A other.html
|
| * f772d66 (refs/original/refs/heads/master) Login page
| | A login.html
| * cb14efd Remove DVD-rip
| | D oops.iso
| * ce36c98 Careless
|/ A oops.iso
| A other.html
|
* 5af4522 Admin page
| A admin.html
* e738b63 Index
A index.html
Perhatikan bahwa komit “Careless” yang baru hanya menambahkan other.html
dan bahwa komit “Remove DVD-rip” tidak lagi ada di cabang master. Cabang yang dilabeli refs/original/refs/heads/master
berisi komitmen asli Anda jika Anda melakukan kesalahan. Untuk menghapusnya, ikuti langkah-langkah di "Daftar Periksa untuk Mengecilkan Gudang."
$ git update-ref -d refs/original/refs/heads/master
$ git reflog expire --expire=now --all
$ git gc --prune=now
Untuk alternatif yang lebih sederhana, klon repositori untuk membuang bit yang tidak diinginkan.
$ cd ~/src
$ mv repo repo.old
$ git clone file:///home/user/src/repo.old repo
Menggunakan file:///...
klon URL akan menyalin objek daripada membuat hardlink saja.
Sekarang sejarah Anda adalah:
$ git lola --name-status
* 8e0a11c (HEAD, master) Login page
| A login.html
* e45ac59 Careless
| A other.html
* 5af4522 Admin page
| A admin.html
* e738b63 Index
A index.html
Nama objek SHA1 untuk dua commit pertama ("Index" dan "Admin page") tetap sama karena operasi filter tidak mengubah commit tersebut. "Careless" hilang oops.iso
dan "Halaman login" mendapat induk baru, jadi SHA1 mereka memang berubah.
Rebase interaktif
Dengan riwayat:
$ git lola --name-status
* f772d66 (HEAD, master) Login page
| A login.html
* cb14efd Remove DVD-rip
| D oops.iso
* ce36c98 Careless
| A oops.iso
| A other.html
* 5af4522 Admin page
| A admin.html
* e738b63 Index
A index.html
Anda ingin menghapus oops.iso
dari "Careless" seolah-olah Anda tidak pernah menambahkannya, dan kemudian "Remove DVD-rip" tidak berguna bagi Anda. Dengan demikian, rencana kami melakukan rebase interaktif adalah menjaga “halaman Admin,” sunting “Careless,” dan buang “Remove DVD-rip.”
Menjalankan $ git rebase -i 5af4522
memulai editor dengan konten berikut.
pick ce36c98 Careless
pick cb14efd Remove DVD-rip
pick f772d66 Login page
# Rebase 5af4522..f772d66 onto 5af4522
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#
Menjalankan rencana kami, kami memodifikasinya
edit ce36c98 Careless
pick f772d66 Login page
# Rebase 5af4522..f772d66 onto 5af4522
# ...
Artinya, kita menghapus baris dengan "Hapus DVD-rip" dan mengubah operasi pada "Careless" menjadi edit
daripada pick
.
Simpan-keluar dari editor menjatuhkan kita pada prompt perintah dengan pesan berikut.
Stopped at ce36c98... Careless
You can amend the commit now, with
git commit --amend
Once you are satisfied with your changes, run
git rebase --continue
Seperti yang dikatakan pesan kepada kita, kita berada pada komit “Careless” yang ingin kita edit, jadi kita menjalankan dua perintah.
$ git rm --cached oops.iso
$ git commit --amend -C HEAD
$ git rebase --continue
Yang pertama menghapus file yang menyinggung dari indeks. Yang kedua memodifikasi atau mengubah "Ceroboh" menjadi indeks yang diperbarui dan -C HEAD
memerintahkan git untuk menggunakan kembali pesan komit lama. Akhirnya, git rebase --continue
lanjutkan dengan sisa operasi rebase.
Ini memberikan sejarah:
$ git lola --name-status
* 93174be (HEAD, master) Login page
| A login.html
* a570198 Careless
| A other.html
* 5af4522 Admin page
| A admin.html
* e738b63 Index
A index.html
yang kamu inginkan.