Apakah menghapus cabang di git menghapusnya dari sejarah?

190

Berasal dari svn, baru mulai mengenal git.

Ketika sebuah cabang dihapus di git, apakah itu dihapus dari sejarah?

Di svn, Anda dapat dengan mudah memulihkan cabang dengan mengembalikan operasi hapus (penggabungan terbalik). Seperti semua penghapusan dalam svn, cabang tidak pernah benar-benar dihapus, hanya dihapus dari pohon saat ini.

Jika cabang sebenarnya dihapus dari sejarah di git, apa yang terjadi pada perubahan yang digabungkan dari cabang itu? Apakah mereka dipertahankan?

Ken Liu
sumber

Jawaban:

251

Cabang hanyalah petunjuk untuk melakukan di git. Dalam git, setiap komit memiliki struktur kode sumber yang lengkap, itu adalah struktur yang sangat berbeda dari svn di mana semua cabang dan tag (berdasarkan konvensi) tinggal di 'folder' terpisah dari repositori di samping 'trunk' khusus.

Jika cabang digabung ke cabang lain sebelum dihapus maka semua komit masih akan dapat dijangkau dari cabang lain ketika cabang pertama dihapus. Mereka tetap seperti apa adanya.

Jika cabang dihapus tanpa digabung ke cabang lain maka komit di cabang itu (sampai titik di mana bercabang dari komit yang masih dapat dijangkau) akan tidak lagi terlihat.

Komit masih akan disimpan dalam repositori dan dimungkinkan untuk memulihkannya segera setelah penghapusan, tetapi akhirnya mereka akan menjadi sampah yang dikumpulkan.

CB Bailey
sumber
3
Terima kasih atas jawabannya. Bisakah Anda mengklarifikasi apa yang Anda maksud dengan "setiap komit memiliki pohon sumber lengkap"? Seperti yang saya pahami, setiap commit di git adalah sekumpulan delta yang merujuk kembali ke commit orang tua, bukan seluruh pohon.
Ken Liu
2
@ Liu Liu: Komit berisi pointer ke nol atau lebih komit induk, objek pohon dan beberapa metadata tentang komit. Komit, oleh karena itu secara unik mengidentifikasi pohon sumber pasangan dan, ketika dilihat terhadap induknya, perubahan yang diperkenalkan.
CB Bailey
9
@ Liu Liu: Itu tergantung pada apa yang Anda telah 'mengandung', tapi ya, pada dasarnya setiap komit berisi pohon lengkap. Dalam objek, objek basis data diindeks oleh id sehingga objek dibagi di antara semua objek (pohon dan komit) yang mereferensikannya sehingga overhead penyimpanan tersirat tidak seburuk yang awalnya terdengar. git juga memiliki optimalisasi penyimpanan yang efisien (file paket) yang membuat penggunaan ruang disk lebih efisien.
CB Bailey
22
"akhirnya mereka akan menjadi sampah yang dikumpulkan" - Akhirnya kapan?
BadHorsie
7
@BadHorsie, itu tergantung .
AliOli
86

Dalam Git, cabang hanyalah pointer (referensi) untuk melakukan dalam grafik asiklik diarahkan (DAG) dari komitmen. Ini berarti bahwa menghapus cabang hanya menghapus referensi untuk melakukan, yang mungkin membuat beberapa komitmen dalam DAG tidak dapat dijangkau, sehingga tidak terlihat. Tetapi semua komit yang ada di cabang yang dihapus masih ada di repositori, setidaknya sampai komit yang tidak terjangkau dipangkas (misalnya menggunakan git gc).

Catatan yang git branch -dakan menolak untuk menghapus cabang jika tidak yakin bahwa menghapusnya tidak akan meninggalkan komitmen yang tidak terjangkau. Anda perlu menggunakan yang lebih kuat git branch -Duntuk memaksa penghapusan cabang jika mungkin meninggalkan komitmen yang tidak terjangkau.

Perhatikan juga bahwa komit yang tidak dapat dijangkau, jika ada, hanya komit di antara ujung terakhir dari cabang yang dihapus dan komit yang digabungkan ke cabang lain yang sudah ada, komit yang ditandai, atau titik percabangan; mana yang lebih baru. Misalnya dalam situasi berikut:

---- O ---- * ---- * ---- / M ---- * <- master <- HEAD
     \ /
      \ --. ---- .-- / - x --- y <- cabang yang dihapus

hanya melakukan 'x' dan 'y' akan menjadi tidak dapat dijangkau setelah menghapus cabang.

Jika Anda beroperasi pada cabang yang dihapus dalam gc.reflogExpireperiode tersebut, default 90 hari, Anda akan memiliki tip terakhir dari cabang yang dihapus dicatat dalam reflog HEAD (lihat git reflog show HEAD, atau git log --oneline --walk-reflogs HEAD). Anda harus dapat menggunakan reflog HEAD untuk memulihkan pointer yang dihapus. Perhatikan juga bahwa dalam kasus ini, komit yang tidak dapat dijangkau hanya dalam cabang yang dihapus akan dilindungi dari pemangkasan (penghapusan) dalam gc.reflogExpireUnreachableperiode, yang secara default adalah 30 hari.

Jika Anda tidak dapat menemukan ujung cabang yang baru saja dihapus di reflog untuk HEAD, Anda dapat mencoba menggunakan git fsckuntuk menemukan "komit yang tidak dapat dijangkau <sha1>", dan periksa yang (melalui git show <sha1>atau git log <sha1>) untuk menemukan ujung cabang yang dihapus.

Independen tentang bagaimana Anda menemukan ujung cabang yang dihapus, Anda dapat membatalkan penghapusan, atau lebih tepatnya membuat kembali cabang yang baru saja dihapus menggunakan

git branch <deleted-branch> <found-sha1-id>

Namun perlu dicatat bahwa reflog untuk cabang akan hilang.


Ada juga skrip git-resurrect.shcontrib/ yang membantu menemukan jejak tip cabang dengan nama yang diberikan dan membangkitkan (membatalkan penghapusan) itu.

Jakub Narębski
sumber
1
Luar biasa! git reflog show HEADterdaftar komit dan saya membuat cabang baru seperti yang Anda katakan, sempurna.
Steven Almeroth
2

Jika Anda khawatir tentang cabang yang tidak sengaja terhapus dan tidak memiliki salinan lokal dari repo Anda lagi, ada ekstensi ke server perusahaan Git seperti Gerrit yang akan mendeteksi penulisan ulang riwayat dan penghapusan cabang, akan mencadangkannya di bawah referensi khusus sehingga mereka dapat dipulihkan jika diperlukan dan tidak akan dipangkas dengan pengumpulan sampah. Administrator Gerrit masih dapat menghapus komitmen yang dipilih jika diperlukan karena alasan hukum.

Tercela Nicolai
sumber