Git: Memulihkan cabang (jarak jauh) yang terhapus

95

Saya perlu memulihkan dua cabang Git yang entah bagaimana saya hapus selama push.

Kedua cabang ini dibuat pada sistem yang berbeda dan kemudian didorong ke repositori "bersama" (github) saya.

Di sistem saya, saya (tampaknya) mengambil cabang selama pengambilan:

~/myfolder> git fetch
remote: Counting objects: 105, done.
remote: Compressing objects: 100% (58/58), done.
remote: Total 62 (delta 29), reused 0 (delta 0)
Unpacking objects: 100% (62/62), done.
From github.com:mygiturl
 * [new branch]      contact_page -> origin/contact_page
   731d1bb..e8b68cc  homepage   -> origin/homepage
 * [new branch]      new_pictures -> origin/new_pictures

Tepat setelah itu saya melakukan dorongan untuk mengirim perubahan lokal saya ke repo pusat. Untuk beberapa alasan, cabang-cabang ini dihapus dari sistem lokal saya dan repo pusat:

~/myfolder> git push
Counting objects: 71, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (43/43), done.
Writing objects: 100% (49/49), 4.99 KiB, done.
Total 49 (delta 33), reused 0 (delta 0)
To [email protected]:mygiturl.git
 - [deleted]         contact_page
 + e8b68cc...731d1bb homepage -> homepage (forced update)
   bb7e9f2..e0d061c  master -> master
 - [deleted]         new_pictures
   e38ac2e..bb7e9f2  origin/HEAD -> origin/HEAD
   731d1bb..e8b68cc  origin/homepage -> origin/homepage
   e38ac2e..bb7e9f2  origin/master -> origin/master
 * [new branch]      origin/contact_page -> origin/contact_page
 * [new branch]      origin/new_pictures -> origin/new_pictures

Tidak terlalu mudah untuk melepaskan cabang dari mesin tempat lahir mereka, jadi saya ingin mencoba dan memulihkannya dari tempat saya jika memungkinkan.

Semua informasi git "urungkan" yang saya cari di Google berkaitan dengan pemulihan komit yang hilang. Saya tidak berpikir itu berlaku di sini, karena saya tidak memiliki UID komit untuk cabang ini.

Saya ingin tahu bagaimana saya bisa mendapatkan ini kembali. Saya juga ingin tahu bagaimana mereka dihapus pada awalnya dan bagaimana saya dapat menghindarinya di masa depan.

EDIT: berdasarkan permintaan, inilah konfigurasi repo saya

user.name=Craig Walker
[email protected]
alias.unadd=reset HEAD
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
core.ignorecase=true
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
[email protected]:MyGitURL.git
remote.origin.mirror=true
branch.master.remote=origin
branch.master.merge=refs/heads/master
alias.undo=reset --hard
alias.test=push -f ci HEAD:master
alias.st=status
alias.ci=commit
alias.br=branch
alias.co=checkout
alias.ch=checkout
alias.df=diff
alias.lg=log -p
alias.who=shortlog -s --
remote.ci.url=ContinuousIntegrationGitURL
remote.ci.fetch=+refs/heads/*:refs/remotes/ci/*
branch.photo.remote=origin
branch.photo.merge=refs/heads/photos
remote.foo.url=FooGitURL
remote.foo.fetch=+refs/heads/*:refs/remotes/cynthia/*
branch.homepage.remote=origin
branch.homepage.merge=refs/heads/homepage
Craig Walker
sumber
Sepertinya Anda memiliki konfigurasi pengambilan dan push yang 'tidak biasa' atau tidak cocok. Apa yang git config -lditampilkan untuk repositori lokal?
CB Bailey
Sangat mungkin; Saya telah mempostingnya.
Craig Walker
2
remote.origin.fetchReferensi Anda tidak sesuai untuk digunakan dengan remote.origin.mirror = true. Apakah Anda ingin melakukan mirror atau Anda ingin menggunakan repo GitHub sebagai remote biasa? Jawaban saya harus memiliki perintah yang Anda butuhkan.
Chris Johnsen
Saya menebak bahwa dengan repositori ke-2, mirroring tidak lagi menjadi pilihan (ini mungkin menyebabkan penghapusan di tempat pertama).
Craig Walker

Jawaban:

103

Saya bukan seorang ahli. Tapi kamu bisa mencobanya

git fsck --full --no-reflogs | grep commit

untuk menemukan komit HEAD dari cabang yang dihapus dan mendapatkannya kembali.

iamamac
sumber
Saya mencoba fsck sebelumnya; apakah Anda tahu cara mengetahui komit mana yang benar? Aku punya 20 untuk dicoba.
Craig Walker
1
Ini berhasil; setelah saya mendapatkan pesan komit, git branch <uid>mendapatkannya kembali. Terima kasih!
Craig Walker
Senang mendengarnya. Pastikan juga untuk menyelesaikan konflik antara pengaturan remotes.origin.mirrordan Anda remotes.origin.fetch, jika tidak, Anda pasti akan mengalami masalah lagi (atau secara tidak sengaja clobber melakukan dorongan dari repo lain).
Chris Johnsen
@Craig: Senang bisa membantu :)
iamamac
3
Saya kehilangan cabang kandidat rilis hari ini. Tidak tahu id komit. Dapat dipulihkan dengan menggunakan:git fsck --full --no-reflogs | cut -d' ' -f3 | xargs -P8 git log --oneline | grep 'Release 2.60.0.157'
spezifanta
23

hanya dua perintah yang menyelamatkan hidup saya

1. Ini akan mencantumkan semua HEAD sebelumnya

git reflog

2. Ini akan mengembalikan HEAD ke commit yang telah Anda hapus.

git reset --hard <your deleted commit>
ex. git reset --hard b4b2c02
chinnawatp.dll
sumber
1
Saya tidak pernah memeriksa ke cabang secara lokal sehingga KEPALA saya tidak pernah ke sana, oleh karena itu saya tidak dapat menemukan ID komit dengan git reflog. Apakah ada hal lain yang bisa saya coba?
zyy
1
Sama seperti @zyy Komit telah dihapus oleh anggota tim lain di jarak jauh, jadi saya harus mendapatkannya kembali di komputer lokal saya (saya tidak pernah memiliki komit secara lokal) dan mendorongnya kembali ...
OmGanesh
11

Cabang Anda yang dihapus tidak hilang, mereka disalin ke origin / contact_page dan origin / new_pictures “cabang pelacakan jarak jauh” oleh pengambilan yang Anda tunjukkan (mereka juga didorong mundur oleh dorongan yang Anda tunjukkan, tetapi didorong ke refs / remote / origin / bukan refs / heads /). Periksa git log origin/contact_pagedan git log origin/new_pictureslihat apakah salinan lokal Anda "mutakhir" dengan apa pun yang menurut Anda seharusnya ada di sana. Jika ada komit baru yang didorong ke cabang-cabang itu (dari beberapa repo lain) antara pengambilan dan dorongan yang Anda tunjukkan, Anda mungkin telah “kehilangan” itu (tetapi mungkin Anda mungkin dapat menemukannya di repo lain yang terakhir mendorong cabang-cabang itu) .

Ambil / Dorong Konflik

Sepertinya Anda mengambil dalam 'mode jarak jauh' normal (refs / heads / disimpan secara lokal di refs / remote / origin /), tetapi mendorong 'mode cermin' (ref lokal / didorong ke remote refs /) . Periksa .git / config Anda dan rekonsiliasi pengaturan remote.origin.fetchdan remote.origin.push.

Buat Cadangan

Sebelum mencoba perubahan apa pun, buat arsip tar atau zip sederhana atau seluruh repo lokal Anda. Dengan begitu, jika Anda tidak menyukai apa yang terjadi, Anda dapat mencoba lagi dari repo yang dipulihkan.

Opsi A: Konfigurasi ulang sebagai Mirror

Jika Anda bermaksud untuk menggunakan repo jarak jauh Anda sebagai cermin lokal Anda, lakukan ini:

git branch contact_page origin/contact_page &&
git branch new_pictures origin/new_pictures &&
git config remote.origin.fetch '+refs/*:refs/*' &&
git config --unset remote.origin.push &&
git config remote.origin.mirror true

Anda mungkin juga akhirnya ingin menghapus semua ref / remote / origin / refs Anda, karena tidak berguna jika Anda beroperasi dalam mode mirror (cabang normal Anda menggantikan cabang pelacakan jarak jauh yang biasa).

Opsi B: Konfigurasi ulang sebagai Remote Normal

Tetapi karena tampaknya Anda menggunakan repo jarak jauh ini dengan beberapa repo "kerja", Anda mungkin tidak ingin menggunakan mode cermin. Anda bisa mencoba ini:

git config push.default tracking &&
git config --unset remote.origin.push
git config --unset remote.origin.mirror

Kemudian, Anda akhirnya akan ingin menghapus palsu ref / remote / ref asal repo jauh Anda: git push origin :refs/remotes/origin/contact_page :refs/remotes/origin/new_pictures ….

Uji Dorong

Cobalah git push --dry-rununtuk melihat apa yang git pushakan dilakukannya tanpa membuatnya membuat perubahan apa pun pada repo jarak jauh. Jika Anda tidak menyukai apa yang dikatakannya akan dilakukan, pulihkan dari cadangan Anda (tar / zip) dan coba opsi lain.

Chris Johnsen
sumber
1
Saya tidak berpikir cabang pelacakan jarak jauh disimpan, jika mereka disalin sama sekali. 'git branch -a' tidak menampilkannya, dan saya juga tidak dapat menemukan file dengan nama tersebut di .git dir. Terakhir, perintah "git log" yang Anda rekomendasikan mengembalikan "fatal: argumen ambigu 'origin / contact_page': revisi yang tidak diketahui atau jalur yang tidak ada di pohon kerja": - \ Terima kasih.
Craig Walker
1
Nah, cabang-cabang itu ada di sana, log push Anda menunjukkannya. Saat mencari referensi di .gitdir, pastikan untuk memeriksa .git/packed_refssebagai tambahan .git/refs/. git show-refakan membuang semua referensi lokal Anda (dikemas atau 'longgar'). Anda masih dapat menemukan ref di repo yang awalnya mendorong mereka ke repo GitHub Anda (di mesin yang berbeda? Repo orang lain?). Kegagalan itu, selama Anda tidak melakukan gc atau prune, Anda harus dapat dengan git fsckkeluaran untuk memeriksa komit menjuntai dan pasang kembali mereka: git branch contact_page-recovered <SHA-1-of-dangling-commit>.
Chris Johnsen
pack_refs juga tidak memilikinya. Komitmen itu pasti menggantung; tidak tahu bagaimana itu terjadi. Terima kasih atas bantuan Anda!
Craig Walker
8

Jika penghapusannya cukup baru (Seperti momen Oh-TIDAK!), Anda masih akan mendapatkan pesan:

Deleted branch <branch name> (was abcdefghi).

Anda masih bisa berlari:

git checkout abcdefghi

git checkout -b <some new branch name or the old one>

Timmy
sumber
8
  1. cari tahu id coimmit

    git reflog

  2. memulihkan cabang lokal yang Anda hapus karena kesalahan

    git branch need-recover-branch-name commitId

  3. dorong perlu-pulihkan-cabang-nama lagi jika Anda menghapus cabang jauh sebelumnya

    git push origin need-recover-branch-name

JackChouMine
sumber
2
Ini berhasil untuk saya. Saya lebih suka jawaban yang diterima karena langkahnya jauh lebih sedikit. Saya bisa melihat pesan commit saya dari git reflog, daripada harus menebak dan git show.
theUtherSide
3

Data masih ada di github, Anda dapat membuat cabang baru dari data lama:

git checkout origin/BranchName #get a readonly pointer to the old branch
git checkout –b BranchName #create a new branch from the old
git push origin BranchName #publish the new branch
jhilden.dll
sumber
1

Saya pikir Anda memiliki konfigurasi yang tidak cocok untuk 'fetch' dan 'push' sehingga ini menyebabkan default fetch / push tidak melakukan round trip dengan benar. Untungnya Anda telah mengambil cabang yang kemudian Anda hapus sehingga Anda harus dapat membuatnya kembali dengan dorongan eksplisit.

git push origin origin/contact_page:contact_page origin/new_pictures:new_pictures
CB Bailey
sumber
Mengenai komentar saya untuk @Chris Johnson, tampaknya cabang tidak lagi (tidak pernah?) Ada secara lokal. Ketika saya git push origin origin/contact_page:contact_pagemendapatkan ini: error: src refspec origin/contact_page does not match any
Craig Walker
Oke, saya rasa saya mengerti apa yang terjadi, (meskipun kesalahan penuh akan membantu). push telah memperbarui cabang yang dihapus dan menghapus ref secara lokal serta ref pelacakan. Apa yang git rev-parse refs/remotes/origin/origin/contact_pagedikatakannya? Karena konfigurasi 'mirror' palsu, cabang my sekarang direferensikan di sini di repositori lokal.
CB Bailey
Hai Charles; Sejak saya menulis ini, saya telah menyesuaikan (dan memperbaiki) konfigurasi saya sehingga saya tidak bisa mendapatkan output rev-parse (berarti) lagi. Namun, menurut saya tidak ada direktori "asal" bersarang ganda di remote.
Craig Walker
0

Jika organisasi Anda menggunakan JIRA atau sistem serupa lainnya yang terkait dengan git, Anda dapat menemukan komit yang tercantum di tiket itu sendiri dan mengklik tautan ke perubahan kode. Github menghapus cabang tersebut tetapi masih memiliki komit yang tersedia untuk pengambilan ceri.

Roralee
sumber
-1

Ini mungkin tampak terlalu berhati-hati, tetapi saya sering membuat zip salinan apa pun yang telah saya kerjakan sebelum saya membuat perubahan kontrol sumber. Dalam proyek Gitlab yang sedang saya kerjakan, saya baru-baru ini menghapus cabang jarak jauh secara tidak sengaja yang ingin saya pertahankan setelah menggabungkan permintaan penggabungan. Ternyata yang harus saya lakukan untuk mendapatkannya kembali dengan riwayat komit adalah mendorong lagi. Permintaan penggabungan masih dilacak oleh Gitlab, jadi masih menunjukkan label 'gabungan' berwarna biru di sebelah kanan cabang. Saya masih membuat zip folder lokal saya jika terjadi sesuatu yang buruk.

Artorias 2718
sumber