Bisakah saya memulihkan cabang setelah dihapus di Git?

1067

Jika saya lari git branch -d XYZ, apakah ada cara untuk memulihkan cabang? Apakah ada cara untuk kembali seolah-olah saya tidak menjalankan perintah delete branch?

prosseek
sumber
4
Catatan yang benar-benar luar biasa untuk membuat jawaban yang diterima adalah bahwa ia berfungsi bahkan jika cabang itu telah dihapus asalnya! Saya baru saja memulihkan beberapa cabang yang tidak lagi saya miliki secara lokal setelah sengaja dihapus.
theblang

Jawaban:

1955

Ya, Anda harus dapat melakukan git reflogdan menemukan SHA1 untuk komit di ujung cabang yang Anda hapus, lalu adil git checkout [sha]. Dan begitu Anda berkomitmen, Anda dapat git checkout -b [branchname]membuat ulang cabang dari sana.


Kredit ke @Cascabel untuk versi kental / satu baris ini.

Anda dapat melakukannya dalam satu langkah:

git checkout -b <branch> <sha>
tfe
sumber
477
Anda dapat melakukannya dalam satu langkah: git checkout -b <branch> <sha>.
Cascabel
200
Kiat cepat - jika Anda baru saja menghapus cabang, Anda akan melihat sesuatu seperti ini di terminal Anda - "Cabang yang dihapus <Anda-branch> (tadinya <sha>)". Dan itu sangat mudah - gunakan saja <sha>. Misalnya seperti yang disebutkan di atas -git checkout -b <branch> <sha>
Snowcrash
6
ya cukup gulirkan ke terminal Anda (kecuali Anda melakukannya CMD+K)
neaumusic
42
Gunakan git reflog --no-abbrevuntuk melihat penuh <sha>yang disingkat secara default.
jkulak
5
Untuk orang lain seperti saya, yang kesulitan menemukan sha dari cabang yang dihapus: Saya bisa git checkout remotes/origin/deleted_branch.
Jeff Irwin
161

Sebagian besar waktu komitmen yang tidak terjangkau berada di reflog. Jadi, hal pertama yang harus dicoba adalah melihat reflog menggunakan perintah git reflog(yang menampilkan reflog untuk HEAD).

Mungkin sesuatu yang lebih mudah jika komit adalah bagian dari cabang tertentu yang masih ada adalah dengan menggunakan perintah git reflog name-of-my-branch. Ini juga berfungsi dengan remote, misalnya jika Anda memaksakan push (saran tambahan: selalu lebih suka git push --force-with-leasemencegah kesalahan yang lebih baik dan lebih dapat dipulihkan).


Jika komit Anda tidak ada dalam reflog Anda (mungkin karena dihapus oleh alat pihak ke-3 yang tidak menulis di reflog), saya berhasil memulihkan cabang dengan menyetel ulang cabang saya ke sha dari commit yang ditemukan menggunakan perintah seperti itu (itu membuat file dengan semua komit yang menggantung):

git fsck --full --no-reflogs --unreachable --lost-found | grep commit | cut -d\  -f3 | xargs -n 1 git log -n 1 --pretty=oneline > .git/lost-found.txt

Jika Anda harus menggunakannya lebih dari satu kali (atau ingin menyimpannya di suatu tempat), Anda juga dapat membuat alias dengan perintah itu ...

git config --global alias.rescue '!git fsck --full --no-reflogs --unreachable --lost-found | grep commit | cut -d\  -f3 | xargs -n 1 git log -n 1 --pretty=oneline > .git/lost-found.txt'

dan menggunakannya dengan git rescue

Untuk menyelidiki komit yang ditemukan, Anda dapat menampilkan setiap komit menggunakan beberapa perintah untuk memeriksanya.

Untuk menampilkan metadata komit (penulis, tanggal pembuatan dan pesan komit):

git cat-file -p 48540dfa438ad8e442b18e57a5a255c0ecad0560

Untuk melihat juga perbedaan:

git log -p 48540dfa438ad8e442b18e57a5a255c0ecad0560

Setelah Anda menemukan komit Anda, kemudian buat cabang di komit ini dengan:

git branch commit_rescued 48540dfa438ad8e442b18e57a5a255c0ecad0560

Untuk yang berada di bawah Windows dan suka GUI, Anda dapat dengan mudah memulihkan komit (dan juga file bertahap yang tidak dikomit) dengan GitExtensions dengan menggunakan fitur Repository=> Git maintenance=>Recover lost objects...


Perintah serupa untuk dengan mudah memulihkan file bertahap dihapus: https://stackoverflow.com/a/58853981/717372

Philippe
sumber
2
Bantuan besar Saya kehilangan komitmen yang tidak pernah ada di repo lokal saya. Perintah pertama yang Anda miliki di sana membantu saya menemukannya di server. +1
Sean Adkinson
1
alias penyelamatan git itu adalah anugerah !!! Terima kasih banyak telah berkontribusi!
72A12F4E
2
Kau telah menyelamatkan hidupku.
Jed Lynch
Jawaban Patrick Koorevaar membantu saya, karena saya tidak tahu komit bercabang yang terakhir saya hapus <sha>.
Monir Khan
@ Monir-Khan Dan? Apa yang harus saya simpulkan? Patrick menjawab hanyalah salinan / tempel dari perintah saya (dengan kesalahan: ia lupa memfilter komit) ...
Philippe
45

Jika Anda suka menggunakan GUI, Anda dapat melakukan seluruh operasi dengan gitk.

gitk --reflog

Ini akan memungkinkan Anda untuk melihat riwayat komit cabang seolah-olah cabang belum dihapus. Sekarang cukup klik kanan pada komit terbaru ke cabang dan pilih opsi menu Create new branch.

bangsawan
sumber
28

Solusi pilihan teratas sebenarnya lebih dari yang diminta:

git checkout <sha>
git checkout -b <branch>

atau

git checkout -b <branch> <sha>

memindahkan Anda ke cabang baru bersama dengan semua perubahan terbaru yang Anda mungkin lupa untuk komit. Ini mungkin bukan niat Anda, terutama ketika dalam "mode panik" setelah kehilangan cabang.

Solusi yang lebih bersih (dan lebih sederhana) tampaknya adalah one-liner (setelah Anda menemukan <sha>dengan git reflog):

git branch <branch> <sha>

Sekarang, cabang Anda saat ini atau perubahan yang tidak dikomit tidak terpengaruh. Sebaliknya, hanya cabang baru yang akan dibuat hingga<sha> .

Jika bukan tip, itu masih akan berfungsi dan Anda mendapatkan cabang yang lebih pendek, maka Anda dapat mencoba lagi dengan <sha>nama cabang baru dan baru sampai Anda melakukannya dengan benar.

Akhirnya, Anda dapat mengubah nama cabang yang berhasil dipulihkan menjadi nama atau apa pun namanya:

git branch -m <restored branch> <final branch>

Tidak perlu dikatakan, kunci sukses adalah menemukan komitmen yang tepat <sha>, jadi sebutkan komitmen Anda dengan bijak :)

Dmitri Zaitsev
sumber
14

Menambah jawaban tfe : ada juga skrip git-resurrect.sh di contrib/area sumber Git (di repositori git.git), yang mungkin membantu Anda.

git-resurrect <name>mencoba menemukan jejak ujung cabang yang disebut <name>, dan mencoba menghidupkannya kembali. Saat ini, reflog sedang mencari pesan checkout, dan dengan -rjuga menggabungkan pesan. Dengan -mdan -t, riwayat semua referensi dipindai untuk Merge <name> into other/ Merge <other> into <name>(masing-masing) melakukan subyek, yang agak lambat tetapi memungkinkan Anda untuk menghidupkan kembali cabang topik orang lain.

Jakub Narębski
sumber
1
Ini bekerja untuk saya sekarang walaupun saya harus menambahkan / usr / lib / git-core / ke PATH saya. Tapi itu tidak melakukan keajaiban yang saya harapkan untuk :(
AmanicA
10

Saya menggunakan perintah berikut untuk menemukan dan mengambil cabang saya yang dihapus. Langkah pertama adalah dari deskripsi gcb.

$ git fsck --full --no-reflogs --unreachable --lost-found > lost
$ cat lost | cut -d\  -f3 > commits
$ cat commits | xargs -n 1 git log -n 1 --pretty=oneline

Sekarang cari git commit id (GIT-SHA) berdasarkan komentar komit dan gunakan dalam perintah di bawah ini. Periksa cabang baru bernama NEW-CABANG dengan GIT-SHA yang ditemukan sebelumnya:

$ git checkout -b NEW-BRANCH GIT-SHA
Patrick Koorevaar
sumber
Terima kasih banyak. Butuh sedikit waktu untuk mencari nama, tetapi waktu sepadan. Jika ada cara untuk juga mencari di komit string pesan, akan jauh lebih baik.
Monir Khan
9

Jika Anda tidak memiliki reflog, mis. karena Anda bekerja di repositori kosong yang tidak mengaktifkan reflog dan komit yang ingin Anda pulihkan dibuat baru-baru ini, opsi lain adalah menemukan objek komit yang baru dibuat dan melihatnya.

Dari dalam .git/objectsdirektori run:

find . -ctime -12h -type f | sed 's/[./]//g' | git cat-file --batch-check | grep commit

Ini menemukan semua objek (komit, file, tag, dll.) Dibuat dalam 12 jam terakhir dan memfilternya untuk menunjukkan hanya komit. Memeriksa ini kemudian merupakan proses yang cepat.

Saya akan mencoba skrip git-ressurect.sh yang disebutkan dalam jawaban Jakub terlebih dahulu.

Robert Knight
sumber
1
Ide alternatif yang bagus! Perintah Anda membuat kesalahan. Masalahnya adalah dengan bagian "12h" (sebenarnya "h"). Setelah saya menghapus "h" itu bekerja dengan baik. Dari man find: "-ctime n - Status file terakhir diubah n * 24 jam yang lalu." Jadi kita juga harus mengubah 12 menjadi 0,5 untuk memiliki perilaku yang diharapkan dari 12 jam terakhir.
pagliuca
1
Saya menggunakan OS X 10.8 di sini, jadi bendera 'temukan' di atas didasarkan pada versi yang dikirimkannya.
Robert Knight
1
Ya, tentu masalahnya dengan versi! Itu sebabnya saya memilih jawaban Anda di tempat pertama! Saya baru saja berkomentar sehingga orang-orang menyadari bahwa parameter mungkin berbeda.
pagliuca
9

Untuk pengguna GitHub tanpa Git terpasang:

Jika Anda ingin mengembalikannya dari situs web GitHub , Anda dapat menggunakan API mereka untuk mendapatkan daftar acara terkait repo:

Pertama

  • temukan SHA tersebut (melakukan hash):

    curl -i https://api.github.com/repos/PublicUser/PublicRepo/events

    ... atau untuk repo pribadi:

    curl -su YourUserName https://api.github.com/repos/YourUserName/YourProject/events

    (akan diminta kata sandi GitHub)

    • (Jika repo membutuhkan dua faktor auth, lihat komentar pada jawaban ini di bawah.)

Lanjut

  • buka GitHub dan buat cabang sementara baru yang akan dihapus selamanya ( Chrome lebih disukai).

   • Pergi ke cabang dan hapus yang itu.

   •   Di halaman yang sama, tanpa memuat ulang , buka DevTools, panel Network. Sekarang persiapkan ...

   • Klik pulihkan. Anda akan melihat "baris" baru. Klik kanan padanya dan pilih "Copy as cURL" dan simpan teks ini di beberapa editor.

   • Tambahkan ke akhir baris kode yang disalin, yang ini: -H "Cookie=" .

Anda sekarang harus mendapatkan sesuatu seperti:

    curl 'https://github.com/UserName/ProjectName/branches?branch=BranchSHA&name=BranchName' -H 'Cookie:' -H 'Origin: https://github.com' -H 'Accept-Encoding: gzip, deflate, br' -H 'Accept-Language: en-US' -H 'User-Agent: User-Agent' -H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' -H 'Accept: */*' -H 'Referer: https://github.com/UserName/ProjectName/branches' -H 'X-Requested-With: XMLHttpRequest' -H 'Connection: keep-alive' --data 'utf8=%E2%9C%93&authenticity_token=token' --compressed

Langkah terakhir

  • ganti "BranchSHA" dengan SHA-hash dan BranchName Anda dengan nama yang diinginkan (BTW, ini adalah retasan hebat untuk mengganti nama cabang dari web). Jika Anda tidak terlalu lambat, Anda harus membuat permintaan ini. Misalnya, cukup salin-tempel ke terminal.

PS

Saya menyadari ini mungkin bukan solusi "paling sederhana" atau "tepat", tetapi ditawarkan jika seseorang merasa itu berguna.

Maxim Mazurok
sumber
1
Di atas adalah salah satu dari sedikit di luar sana yang tidak bergantung git reflogdan karena itu berguna misalnya ketika telah menghapus cabang jauh dan kehilangan akses ke komputer yang dilakukan dari sehingga tidak ada pilek berguna yang didapat reflog. Catatan saat menggunakan OAuth atau autentikasi dua faktor pada Github , curlperintah tersebut menjadi dalam bentuk: curl -u username:token https://api.github.com/userataucurl -H "Authorization: token TOKEN" https://api.github.com/repos/USER_OR_ORG_NAME/REPO_NAME/events
TT--
@ TT-- wow, saya senang itu membantu! dan terima kasih atas kontribusi Anda mengenai token
autentik
8

Dari pemahaman saya jika cabang yang akan dihapus dapat dijangkau oleh cabang lain, Anda dapat menghapusnya dengan aman

git branch -d [branch]

dan pekerjaanmu tidak hilang. Ingatlah bahwa suatu cabang bukanlah snapshot, tetapi sebuah penunjuk ke yang satu. Jadi, ketika Anda menghapus cabang, Anda menghapus pointer.

Anda bahkan tidak akan kehilangan pekerjaan jika Anda menghapus cabang yang tidak dapat dijangkau oleh cabang lainnya. Tentu saja itu tidak akan semudah memeriksa hash komit, tetapi Anda masih bisa melakukannya. Itu sebabnya Git tidak dapat menghapus cabang yang tidak dapat dijangkau dengan menggunakan -d. Sebaliknya Anda harus menggunakan

git branch -D [branch]

Ini adalah bagian dari video yang harus ditonton dari Scott Chacon tentang Git. Periksa menit 58:00 ketika ia berbicara tentang cabang dan bagaimana menghapusnya.

Pengantar Git dengan Scott Chacon dari GitHub

fabiopagoti
sumber
7
Bagaimana ini membantu menjawab pertanyaan?
Dmitri Zaitsev
6
Memberitahu penanya bahwa cabang tidak memegang konten tetapi sebenarnya adalah petunjuk. Anda tidak perlu takut menghapus cabang .. Anda dapat membuat yang baru menunjuk ke komit yang sama dengan yang dihapus .... Wow! Saya masih ingat ketika saya mengajukan pertanyaan ini. Waktu yang baik kembali ke 2012!
fabiopagoti
1
Harus gulir tiga layar ke ATLAST menemukan jawaban yang mengatasi masalah: menghapus cabang adalah menghapus pointer belaka. Tidak ada situasi kehilangan data di sini, satu-satunya hal yang harus dipulihkan adalah kemana arahnya. Jawaban siapa yang langsung ke refloghanya berlebihan.
RomainValeri
5

Pastikan untuk melakukan semua ini secara lokal, dan konfirmasikan repo Anda berada dalam kondisi yang Anda inginkan sebelum mendorong ke Bitbucket Cloud. Mungkin juga merupakan ide bagus untuk mengkloning repo Anda saat ini, dan menguji solusi ini terlebih dahulu.

  1. Jika Anda baru saja menghapus cabang, Anda akan melihat sesuatu seperti ini di terminal Anda:
    Deleted branch <your-branch> (was <sha>)

2. Untuk mengembalikan cabang, gunakan:

    git checkout -b <branch> <sha>

Jika Anda tidak tahu 'sha' di atas kepala Anda, Anda dapat:

  1. Temukan 'sha' untuk komit di ujung cabang Anda yang dihapus menggunakan:
    git reflog
  1. Untuk memulihkan cabang, gunakan:
    git checkout -b <branch> <sha>

Jika komit Anda tidak ada dalam reflog Anda:

  1. Anda dapat mencoba memulihkan cabang dengan mengatur ulang cabang Anda ke sha dari komit yang ditemukan menggunakan perintah seperti:
    git fsck --full --no-reflogs --unreachable --lost-found | grep commit | cut -d\  -f3 | xargs -n 1 git log -n 1 --pretty=oneline > .git/lost-found.txt

2. Anda kemudian dapat menampilkan setiap komit menggunakan salah satu dari ini:

    git log -p <commit>
    git cat-file -p <commit>
uyghurbeg
sumber
4

Untuk memulihkan cabang yang dihapus, Pertama-tama buka sejarah reflog,

git reflog -n 60

Dimana n mengacu pada n terakhir yang dilakukan. Kemudian temukan kepala yang tepat dan buat cabang dengan kepala itu.

git branch testbranch HEAD@{30}
sajin tm
sumber
4

Saya mengubah cabang dari jarak jauh untuk mencoba menghapus beberapa komitmen yang tidak saya inginkan dan akan memilih yang tepat yang saya inginkan. Tentu saja saya salah menulis SHA ...

Inilah cara saya menemukannya (sebagian besar antarmuka / interaksi yang lebih mudah dari hal-hal pada jawaban di sini):

Pertama, buat daftar komitmen longgar di log Anda. Lakukan ini sesegera mungkin dan berhenti bekerja, karena mungkin dibuang oleh pengumpul sampah.

git fsck --full --no-reflogs --unreachable --lost-found > lost

Ini membuat lostfile dengan semua komit yang harus Anda lihat. Untuk menyederhanakan hidup kita, mari kita potong saja SHA darinya:

cat lost | cut -d\  -f3 > commits

Sekarang Anda memiliki commitsfile dengan semua komitmen yang harus Anda perhatikan.

Dengan asumsi Anda menggunakan Bash, langkah terakhir:

for c in `cat commits`; do  git show $c; read; done

Ini akan menunjukkan kepada Anda perbedaan dan komit informasi untuk masing-masing dari mereka. Dan menunggu Anda menekan Enter. Sekarang tulis semua yang Anda inginkan, lalu pilih-ceri. Setelah Anda selesai, cukup Ctrl-C saja.

gcb
sumber
1

Pertama pergi ke git batch perpindahan ke proyek Anda seperti:

cd android studio project
cd Myproject
then type :
git reflog

Anda semua memiliki daftar perubahan dan nomor referensi ambil nomor ref kemudian checkout
dari studio android atau dari git betcha. solusi lain ambil nomor ref dan buka android studio klik pada cabang git ke bawah lalu klik pada checkout tag atau revisi melewati nomor referensi lalu lol Anda memiliki cabang.

FAHAD HAMMAD ALOTAIBI
sumber
1

Menambah jawaban Anda, Anda dapat memulihkan dengan proses ini disebutkan, kecuali jika komit tidak mengumpulkan sampah. Cabang Git hanyalah sebuah pointer ke komit tertentu di pohon komit. Tetapi jika Anda menghapus pointer, dan komit pada cabang itu tidak digabung ke cabang lain yang ada, maka git memperlakukannya sebagai menggantung komit dan menghapusnya selama pengumpulan sampah, yang dapat berjalan secara otomatis secara berkala.

Jika cabang Anda tidak digabung ke cabang yang ada, dan jika itu adalah sampah yang dikumpulkan, maka Anda akan kehilangan semua komitmen sampai titik dari mana cabang itu bercabang dari cabang yang ada.

Rajeshwar Agrawal
sumber
1

Masalah terkait: Saya membuka halaman ini setelah mencari "bagaimana cara mengetahui apa yang dihapus cabang".

Saat menghapus banyak cabang lama, saya merasa salah menghapus cabang yang baru, tetapi tidak tahu nama untuk memulihkannya.

Untuk mengetahui cabang apa yang dihapus baru-baru ini, lakukan hal berikut:

Jika Anda membuka URL Git Anda, yang akan terlihat seperti ini:

https://your-website-name/orgs/your-org-name/dashboard

Kemudian Anda dapat melihat umpan, dari apa yang dihapus, oleh siapa, di masa lalu.

Manohar Reddy Poreddy
sumber
Tentu. Jawaban di atas adalah untuk GitHub. Kami memasang GitHub secara lokal. Terima kasih telah mengajukan pertanyaan.
Manohar Reddy Poreddy
1

Saya melakukan ini di komputer yang saya hapus cabang:

git reflog

tanggapan:

74b2383 (develope) HEAD@{1}: checkout: moving from master to develope
40ef328 (HEAD -> master, origin/master, origin/HEAD) HEAD@{2}: checkout: moving from develope to master
74b2383 (develope) HEAD@{3}: checkout: moving from master to develope
40ef328 (HEAD -> master, origin/master, origin/HEAD) HEAD@{4}: reset: moving to HEAD
40ef328 (HEAD -> master, origin/master, origin/HEAD) HEAD@{5}: clone: from http://LOCALGITSERVER/myBigProject/Android.git

dan saya mengambil cabang dengan perintah ini:

git checkout -b newBranchName 74b2383

Ammar Bozorgvar
sumber
0

Hanya menggunakan git reflogtidak mengembalikan shauntuk saya. Hanya commit id(yang panjangnya 8 karakter dan sha yang lebih panjang)

Jadi saya menggunakan git reflog --no-abbrev

Dan kemudian lakukan hal yang sama seperti yang disebutkan di atas: git checkout -b <branch> <sha>

MarvinVK
sumber
Anda selalu dapat menggunakan sha 8 karakter disingkat, Anda tidak harus menggunakan sha penuh
Michael Dreher
0

JIKA Anda menggunakan VSCode ... dan Anda menyinkronkan cabang Anda dengan server di beberapa titik sebelum menghapusnya ...

Perhatikan bahwa penghapusan cabang git hanya menghapus salinan lokal, bukan salinan di server. Pertama, di panel Git (ikon git di bilah alat kiri), lihat melalui cabang dan lihat apakah cabang Anda masih ada di bawah "origin / your_branch_name". Jika demikian, cukup pilih itu dan Anda harus mendapatkan kode Anda kembali (menyarankan agar Anda segera menyalin / menempel / menyimpannya secara lokal di tempat lain).

Jika Anda tidak melihat "origin / your_branch_name", Instal ekstensi GitLens. Ini memungkinkan Anda untuk melihat secara visual di dalam repositori server dan menemukan salinan yang Anda sinkronkan ke server. Jika Anda memiliki beberapa repositori, perhatikan bahwa mungkin perlu membuka setidaknya satu file dari repositori yang diinginkan untuk membuat repositori muncul di GitLens. Kemudian:

  1. Buka panel GitLens

  2. Perluas repositori

  3. Anda akan melihat daftar kategori: Cabang / Kontributor / Remote / Stash / dll

Anda harus menemukan YourLostTreasure di bawah "Branches" atau mungkin di bawah "Remote -> Origins". Mudah-mudahan, Anda akan melihat cabang dengan nama yang diinginkan - jika Anda mengembangkannya, Anda akan melihat file yang Anda ubah di cabang itu. Klik dua kali nama file untuk membukanya, dan segera buat cadangan kode itu.

Jika Anda tidak segera melihat cabang Anda yang hilang, cari-cari dan jika Anda menemukan sesuatu yang menjanjikan, segera buka dan ambil kodenya. Saya harus melihat-lihat sedikit sampai saya menemukan TheGoldenBranch, dan bahkan kemudian kode itu hilang satu atau dua penyelamatan terakhir (mungkin karena saya gagal menyinkronkan ke server sebelum mencoba-a-Branch-Merge-tetapi-secara tidak sengaja mengklik - Cabang-Hapus). Pencarian saya tidak perlu diperpanjang karena ketika saya pertama kali menemukan cabang saya tidak sepenuhnya yakin nama itu benar sehingga terus mencari, dan butuh beberapa waktu untuk menemukan kembali cabang pertama itu. (Karenanya, Carpe Carpum lalu terus mencari.)

cssyphus
sumber