Bagaimana saya bisa membatalkan git reset --hard HEAD ~ 1?


1159

Apakah mungkin untuk membatalkan perubahan yang disebabkan oleh perintah berikut? Jika ya, bagaimana caranya?

git reset --hard HEAD~1

8
Saya telah menulis panduan lengkap untuk memulihkan komit yang hilang dengan git. Bahkan memiliki ilustrasi :-) [Check it out] [fixLink] [fixLink]: programblings.com/2008/06/07/...
webmat

12
--hardbuang perubahan yang tidak dikomit. Karena ini tidak dilacak oleh git, tidak ada cara untuk mengembalikannya melalui git.
Zaz


1
Ini adalah artikel yang bagus untuk membantu Anda memulihkan file.
Jan Swart

2
Ini adalah sumber yang bagus langsung dari Github: Cara membatalkan (hampir) apa pun dengan Git
jasonleonhard

Jawaban:


1774

Pat Notz benar. Anda bisa mendapatkan komit kembali selama itu sudah dalam beberapa hari. git hanya mengumpulkan sampah setelah sekitar satu bulan atau lebih kecuali Anda secara eksplisit mengatakannya untuk menghapus gumpalan yang lebih baru.

$ git init
Initialized empty Git repository in .git/

$ echo "testing reset" > file1
$ git add file1
$ git commit -m 'added file1'
Created initial commit 1a75c1d: added file1
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 file1

$ echo "added new file" > file2
$ git add file2
$ git commit -m 'added file2'
Created commit f6e5064: added file2
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 file2

$ git reset --hard HEAD^
HEAD is now at 1a75c1d... added file1

$ cat file2
cat: file2: No such file or directory

$ git reflog
1a75c1d... HEAD@{0}: reset --hard HEAD^: updating HEAD
f6e5064... HEAD@{1}: commit: added file2

$ git reset --hard f6e5064
HEAD is now at f6e5064... added file2

$ cat file2
added new file

Anda dapat melihat dalam contoh bahwa file2 telah dihapus sebagai hasil dari hard reset, tetapi diletakkan kembali pada tempatnya ketika saya reset melalui reflog.


222
Anda dapat menggunakan "git reset --hard HEAD @ {1}", tidak perlu menggunakan SHA1. Dalam kebanyakan kasus, itu harus cukup menggunakan "git reset --hard ORIG_HEAD".
Jakub Narębski

39
git log -gbisa menjadi cara yang sedikit lebih baik untuk melihat reflog daripada git reflog.
Dan Moulding

60
Ada satu peringatan yang sangat penting dengan ini .. dan itulah bagian "--hard". --Hard meniup perubahan lokal Anda yang tidak dikomit. Dan Anda tidak bisa mendapatkannya kembali seperti ini (karena mereka belum berkomitmen di mana pun). Saya percaya tidak ada yang dapat Anda lakukan tentang itu :(
Michael Anderson

3
^ Agar Anda tahu bahwa Anda dapat menyembunyikan perubahan lokal Anda sebelum melakukan reset --hard, dan kemudian pop saja itu dan Anda tidak kehilangan apa-apa! Harus cinta git.
Lethjakman

5
Saya lebih suka git reflogdaripada git log -ghanya karena Anda mendapatkan semua informasi pada satu baris dengan sha1, info KEPALA dan melakukan pesan semua berbaris. Jauh lebih mudah dibaca.
Snowcrash

371

Yang ingin Anda lakukan adalah menentukan sha1 dari commit yang ingin Anda pulihkan. Anda bisa mendapatkan sha1 dengan memeriksa reflog ( git reflog) dan kemudian melakukannya

git reset --hard <sha1 of desired commit>

Tapi jangan menunggu terlalu lama ... setelah beberapa minggu git akhirnya akan melihat komit itu sebagai tidak direferensikan dan menghapus semua gumpalan.


2
peringatan untuk diri saya sendiri beberapa menit yang lalu: ini akan mengatur ulang semua modifikasi. itu tidak akan menyentuh file yang tidak dilacak sekalipun.
aexl

175

Jawabannya tersembunyi dalam respons terperinci di atas, Anda cukup melakukannya:

$> git reset --hard HEAD@{1}

(Lihat output dari git reflog show )


17
Perhatikan bahwa ini bukan solusi jika Anda telah membuat perubahan repo lain sejak reset. Lihatlah reflog sebelum menjalankan apa pun.
forresthopkinsa

2
Secara tidak sengaja mengatur ulang repositori saya, mengira pekerjaan saya hilang selamanya. Jawaban ini menyelamatkan hari saya.
Zaiyang Li

woh! Anda benar-benar menyelamatkan saya hari =)
jfcogato

Bagus. Ini sangat membantu.
Prashant Biradar

117

Dimungkinkan untuk memulihkannya jika Git belum mengumpulkan sampah.

Dapatkan ikhtisar komitmen menjuntai dengan fsck:

$ git fsck --lost-found
dangling commit b72e67a9bb3f1fc1b64528bcce031af4f0d6fcbf

Memulihkan komit yang menggantung dengan rebase:

$ git rebase b72e67a9bb3f1fc1b64528bcce031af4f0d6fcbf

1
Itu hal-hal yang luar biasa. Hidup telah diselamatkan.
Mohhamad Hasham

Penjelasan terperinci dapat ditemukan di sini: medium.com/@CarrieGuss/… . Barang yang menyelamatkan hidup.
tuan.dinh

49

Jika Anda benar-benar beruntung, seperti saya sebelumnya, Anda dapat kembali ke editor teks Anda dan menekan 'batalkan'.

Saya tahu itu bukan jawaban yang tepat, tetapi itu menyelamatkan saya dari pekerjaan setengah hari jadi semoga itu akan melakukan hal yang sama untuk orang lain!


3
Ini sebenarnya tip yang sangat bagus, menyelamatkan saya berkali-kali;) Dan caranya lebih sederhana daripada melakukan apa pun di git ...
severin

3
dan terima kasih atas semua kebaikan yang ramah di seluruh dunia ini. Terima kasih. Terima kasih. Terima kasih.
Perjalanan

9
Ini adalah satu-satunya cara untuk memulihkan perubahan yang tidak ditentukan dalam file setelah hard reset. Menyelamatkan saya juga;)
Czarek Tomczak

4
Sebagai petunjuk tambahan, beberapa IDE sebagai gerhana juga menyimpan riwayat file terbaru. Dengan begitu, Anda bahkan mungkin dapat memulihkan perubahan yang lebih lama setelah editor ditutup. Itu berhasil bagi saya.
martin

1
Tuhan memberkatimu Chris
Adam Waite

45

sejauh yang saya tahu, --hardakan membuang perubahan yang tidak dikomit. Karena ini tidak dilacak oleh git. tetapi Anda dapat membatalkan discarded commit.

$ git reflog

akan mendaftar:

b0d059c HEAD@{0}: reset: moving to HEAD~1
4bac331 HEAD@{1}: commit: added level introduction....
....

dimana 4bac331itu discarded commit.

Sekarang cukup gerakkan kepala ke komit itu ::

$ git reset --hard 4bac331

34

Contoh kasus IRL:

$ git fsck --lost-found

Checking object directories: 100% (256/256), done.
Checking objects: 100% (3/3), done.
dangling blob 025cab9725ccc00fbd7202da543f556c146cb119
dangling blob 84e9af799c2f5f08fb50874e5be7fb5cb7aa7c1b
dangling blob 85f4d1a289e094012819d9732f017c7805ee85b4
dangling blob 8f654d1cd425da7389d12c17dd2d88d318496d98
dangling blob 9183b84bbd292dcc238ca546dab896e073432933
dangling blob 1448ee51d0ea16f259371b32a557b60f908d15ee
dangling blob 95372cef6148d980ab1d7539ee6fbb44f5e87e22
dangling blob 9b3bf9fb1ee82c6d6d5ec9149e38fe53d4151fbd
dangling blob 2b21002ca449a9e30dbb87e535fbd4e65bac18f7
dangling blob 2fff2f8e4ea6408ac84a8560477aa00583002e66
dangling blob 333e76340b59a944456b4befd0e007c2e23ab37b
dangling blob b87163c8def315d40721e592f15c2192a33816bb
dangling blob c22aafb90358f6bf22577d1ae077ad89d9eea0a7
dangling blob c6ef78dd64c886e9c9895e2fc4556e69e4fbb133
dangling blob 4a71f9ff8262701171d42559a283c751fea6a201
dangling blob 6b762d368f44ddd441e5b8eae6a7b611335b49a2
dangling blob 724d23914b48443b19eada79c3eb1813c3c67fed
dangling blob 749ffc9a412e7584245af5106e78167b9480a27b
dangling commit f6ce1a403399772d4146d306d5763f3f5715cb5a    <- it's this one

$ git show f6ce1a403399772d4146d306d5763f3f5715cb5a

commit f6ce1a403399772d4146d306d5763f3f5715cb5a
Author: Stian Gudmundsen Høiland <stian@Stians-Mac-mini.local>
Date:   Wed Aug 15 08:41:30 2012 +0200

    *MY COMMIT MESSAGE IS DISPLAYED HERE*

diff --git a/Some.file b/Some.file
new file mode 100644
index 0000000..15baeba
--- /dev/null
+++ b/Some.file
*THE WHOLE COMMIT IS DISPLAYED HERE*

$ git rebase f6ce1a403399772d4146d306d5763f3f5715cb5a

First, rewinding head to replay your work on top of it...
Fast-forwarded master to f6ce1a403399772d4146d306d5763f3f5715cb5a.

2
Menggantung gumpalan terdengar seperti monster AD & D!
sbichenko

Terima kasih @Stian Terangkan dengan baik! Saya ingin menambahkan untuk orang lain menemukan jawaban ini bahwa jika Anda memiliki lebih dari satu "menggantung" komit itu tidak yakin bahwa Anda ingin melakukan rebase pada baris terakhir :)
JimiSweden

Acara git menyelamatkan beberapa file saya, terima kasih banyak Bung!
William

32

Dalam kebanyakan kasus, ya.

Bergantung pada keadaan repositori Anda ketika Anda menjalankan perintah, efek dari git reset --hardcan berkisar dari sepele ke membatalkan, pada dasarnya tidak mungkin.

Di bawah ini saya telah membuat daftar berbagai skenario yang mungkin berbeda, dan bagaimana Anda dapat pulih dari itu.

Semua perubahan saya dilakukan, tetapi sekarang komit hilang!

Situasi ini biasanya terjadi ketika Anda menjalankan git resetdengan argumen, seperti pada git reset --hard HEAD~. Jangan khawatir, ini mudah untuk dipulihkan!

Jika Anda hanya berlari git resetdan tidak melakukan hal lain sejak itu, Anda dapat kembali ke posisi semula dengan one-liner ini:

git reset --hard @{1}

Ini akan mereset cabang Anda saat ini dalam keadaan apa pun sebelum diubah terakhir kali (dalam kasus Anda, modifikasi terbaru pada cabang akan menjadi hard reset yang ingin Anda batalkan).

Namun, jika Anda telah melakukan modifikasi lain pada cabang Anda sejak reset, one-liner di atas tidak akan berfungsi. Alih-alih, Anda harus berlari untuk melihat daftar semua perubahan terbaru yang dilakukan pada cabang Anda (termasuk me-reset). Daftar itu akan terlihat seperti ini:git reflog <branchname>

7c169bd master@{0}: reset: moving to HEAD~
3ae5027 master@{1}: commit: Changed file2
7c169bd master@{2}: commit: Some change
5eb37ca master@{3}: commit (initial): Initial commit

Temukan operasi dalam daftar ini yang ingin Anda "batalkan". Pada contoh di atas, itu akan menjadi baris pertama, yang bertuliskan "reset: pindah ke HEAD ~". Kemudian salin representasi komit sebelum (di bawah) operasi itu. Dalam kasus kami, itu akan menjadi master@{1}(atau 3ae5027, keduanya mewakili komit yang sama), dan jalankan git reset --hard <commit>untuk mereset cabang Anda saat ini kembali ke komit itu.

Saya mengadakan perubahan dengan git add, tetapi tidak pernah berkomitmen. Sekarang perubahan saya hilang!

Ini agak sulit untuk dipulihkan. git memang memiliki salinan dari file yang Anda tambahkan, tetapi karena salinan ini tidak pernah terikat pada komit tertentu, Anda tidak dapat mengembalikan perubahan sekaligus. Sebagai gantinya, Anda harus mencari file individual di database git dan mengembalikannya secara manual. Anda dapat melakukan ini menggunakan git fsck.

Untuk detailnya, lihat Undo git reset --hard dengan file yang tidak dikomit di area stage .

Saya memiliki perubahan pada file di direktori kerja saya yang tidak pernah saya laksanakan git add, dan tidak pernah komit. Sekarang perubahan saya hilang!

Uh oh. Aku benci mengatakan ini padamu, tapi kamu mungkin kurang beruntung. git tidak menyimpan perubahan yang tidak Anda tambahkan atau komit padanya, dan sesuai dengan dokumentasi untukgit reset :

--keras

Atur ulang indeks dan pohon kerja. Setiap perubahan pada file yang dilacak di pohon kerja sejak <commit>dibuang.

Ada kemungkinan bahwa Anda mungkin dapat memulihkan perubahan Anda dengan semacam utilitas pemulihan disk atau layanan pemulihan data profesional, tapi pada saat ini itu mungkin masalah lebih dari itu layak.


1
One-liner bekerja untuk saya, terima kasih, tapi saya hanya ingin tahu apa sebenarnya yang "@ {1}" lakukan ..
Stan Bashtavenko

1
@StanB Dokumentasi di sini: git-scm.com/docs/git-rev-parse pada dasarnya mengacu pada entri reflog pertama pada cabang saat ini.
Ajedi32

Terima kasih telah meliput semua kasing. Saya belum berkomitmen atau menambahkan milik saya.
xdhmoore

21

Jika Anda belum mengumpulkan sampah repositori Anda (misalnya menggunakan git repack -datau git gc, tetapi perhatikan bahwa pengumpulan sampah juga dapat terjadi secara otomatis), maka komit Anda masih ada - itu tidak lagi dapat dijangkau melalui HEAD.

Anda dapat mencoba menemukan komit Anda dengan melihat melalui output dari git fsck --lost-found.

Versi Git yang lebih baru memiliki sesuatu yang disebut "reflog", yang merupakan log dari semua perubahan yang dilakukan pada referensi (tidak seperti perubahan yang dilakukan pada konten repositori). Jadi, misalnya, setiap kali Anda mengganti KEPALA Anda (yaitu setiap kali Anda melakukan git checkoutuntuk beralih cabang) yang akan dicatat. Dan, tentu saja, Anda git resetjuga memanipulasi KEPALA, jadi itu juga dicatat. Anda dapat mengakses status lama dari referensi Anda dengan cara yang sama seperti Anda dapat mengakses status lama dari repositori Anda, dengan menggunakan @tanda alih-alih ~, seperti git reset HEAD@{1}.

Butuh beberapa saat untuk memahami apa perbedaan antara HEAD @ {1} dan HEAD ~ 1, jadi inilah sedikit penjelasan:

git init
git commit --allow-empty -mOne
git commit --allow-empty -mTwo
git checkout -b anotherbranch
git commit --allow-empty -mThree
git checkout master # This changes the HEAD, but not the repository contents
git show HEAD~1 # => One
git show HEAD@{1} # => Three
git reflog

Jadi, HEAD~1berarti "pergi ke komit sebelum komit yang ditunjuk HEAD saat ini", sementara HEAD@{1}berarti "pergi ke komit yang ditunjuk HEAD sebelum menunjuk di tempat yang saat ini menunjuk pada".

Itu akan dengan mudah memungkinkan Anda menemukan komit Anda yang hilang dan memulihkannya.


2
Penjelasan lain yang saya pikir akan lebih jelas: KEPALA ~ 1 berarti pergi ke "induk dari KEPALA," sementara KEPALA @ {1} pergi ke "mundur satu langkah dalam sejarah KEPALA"
kizzx2

1
Masalahnya adalah bahwa istilah "sejarah" benar-benar kelebihan beban dalam VCS. Namun cara lain untuk mengekspresikan adalah bahwa ~ mundur ke belakang dalam sejarah commit , sedangkan @ mundur dalam sejarah kronologis atau temporal . Tetapi tidak satu pun dari ketiga versi ini yang sangat baik.
Jörg W Mittag

@ kizzx2 (dan Jorg) sebenarnya 3 penjelasan itu, ketika diambil bersama-sama, banyak membantu - thx
Richard Le Mesurier

14

Sebelum menjawab, mari tambahkan beberapa latar belakang, jelaskan apa ini HEAD.

First of all what is HEAD?

HEADhanyalah referensi ke komit saat ini (terbaru) di cabang saat ini.
Hanya ada satu HEADpada waktu tertentu. (tidak termasuk git worktree)

Konten HEADdisimpan di dalam .git/HEADdan berisi 40 byte SHA-1 dari komit saat ini.


detached HEAD

Jika Anda tidak menggunakan komit terbaru - artinya HEADmenunjuk komit sebelumnya dalam sejarah yang disebut detached HEAD.

masukkan deskripsi gambar di sini

Pada baris perintah akan terlihat seperti ini- SHA-1 bukan nama cabang karena HEADtidak menunjuk ke ujung cabang saat ini

masukkan deskripsi gambar di sini


Beberapa opsi tentang cara memulihkan dari HEAD yang terpisah:


git checkout

git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back

Ini akan mengecek cabang baru yang menunjuk ke komit yang diinginkan.
Perintah ini akan checkout ke komit yang diberikan.
Pada titik ini Anda dapat membuat cabang dan mulai bekerja sejak saat ini.

# Checkout a given commit. 
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>

# create a new branch forked to the given commit
git checkout -b <branch name>

git reflog

Anda selalu dapat menggunakan itu reflogjuga.
git reflogakan menampilkan perubahan apa pun yang memperbarui HEADdan memeriksa entri reflog yang diinginkan akan mengatur HEADkembali komitmen ini.

Setiap kali KEPALA diubah akan ada entri baru di reflog

git reflog
git checkout HEAD@{...}

Ini akan membuat Anda kembali ke komit yang Anda inginkan

masukkan deskripsi gambar di sini


git reset HEAD --hard <commit_id>

"Gerakkan" kepala Anda kembali ke komit yang diinginkan.

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts, if you've modified things which were
# changed since the commit you reset to.
  • Catatan: ( Karena Git 2.7 )
    Anda juga bisa menggunakan itu git rebase --no-autostash.


git revert <sha-1>

"Undo" rentang komit atau komit yang diberikan.
Perintah reset akan "membatalkan" setiap perubahan yang dilakukan dalam komit yang diberikan.
Komit baru dengan undo patch akan dilakukan sementara komit asli akan tetap ada dalam sejarah juga.

# add new commit with the undo of the original one.
# the <sha-1> can be any commit(s) or commit range
git revert <sha-1>

Skema ini menggambarkan perintah mana melakukan apa.
Seperti yang Anda lihat ada reset && checkoutmodifikasi HEAD.

masukkan deskripsi gambar di sini


Tampaknya git reset HEAD --hard <commit_id>contoh Anda diambil dari stackoverflow.com/questions/4114095/... - Jika itu masalahnya, bisakah Anda mengedit dalam atribusi?
Rob

12

git reflog

  • Temukan sha komit Anda di daftar lalu salin dan tempel ke perintah ini:

git cherry-pick <the sha>


1
git-cherry-pick - Terapkan perubahan yang diperkenalkan oleh beberapa commit yang ada. Saya pikir ini sederhana dan sangat membantu dalam konteks ini
Amitesh

1
semua orang benar-benar mencari ini ketika mereka mencari cara untuk membatalkan perubahan hard reset. jawaban ini seharusnya mendapat lebih banyak
dukungan

@ErenL Saya kira saya baru saja tahu, orang-orang suka melakukan pekerjaan ekstra. haha
ScottyBlades

1
Ini dia, kamu baru saja menyelamatkan hariku 🙂
Sylvernus Akubo

11

Saya tahu ini adalah utas lama ... tetapi karena banyak orang mencari cara untuk membatalkan hal-hal di Git, saya masih berpikir itu mungkin ide yang baik untuk terus memberikan kiat di sini.

Ketika Anda melakukan "git add" atau memindahkan apa pun dari kiri atas ke kiri bawah di git gui, isi file disimpan dalam gumpalan dan konten file dimungkinkan untuk pulih dari gumpalan itu.

Jadi dimungkinkan untuk memulihkan file bahkan jika itu tidak dilakukan tetapi harus ditambahkan.

git init  
echo hello >> test.txt  
git add test.txt  

Sekarang gumpalan dibuat tetapi direferensikan oleh indeks sehingga tidak akan terdaftar dengan git fsck sampai kita mengatur ulang. Jadi kami mengatur ulang ...

git reset --hard  
git fsck  

Anda akan mendapatkan gumpalan menggantung ce013625030ba8dba906f756967f9e9ca394464a

git show ce01362  

akan memberi Anda konten file "halo" kembali

Untuk menemukan komitmen yang tidak direferensikan, saya menemukan tip di suatu tempat menyarankan ini.

gitk --all $(git log -g --pretty=format:%h)  

Saya memilikinya sebagai alat di git gui dan itu sangat berguna.


+1. Seperti disebutkan dalam stackoverflow.com/a/21350689/6309 , git fsck --lost-founddapat membantu.
VonC

7

Jika Anda menggunakan JetBrains IDE (apa pun yang berbasis IntelliJ), Anda bahkan dapat memulihkan perubahan yang tidak dikomit melalui fitur "Sejarah Lokal" mereka.

Klik kanan pada direktori tingkat atas Anda di pohon file Anda, cari "Sejarah Lokal" di menu konteks, dan pilih "Tampilkan Riwayat". Ini akan membuka tampilan tempat pengeditan terakhir Anda dapat ditemukan, dan setelah Anda menemukan revisi yang ingin Anda kembalilah, klik kanan padanya dan klik "Kembalikan".



3

Buat skrip kecil agar lebih mudah menemukan komit yang dicari:

git fsck --lost-found | grep commit | cut -d ' ' -f 3 | xargs -i git show \{\} | egrep '^commit |Date:'

Ya, itu bisa dibuat jauh lebih cantik dengan awk atau sesuatu seperti itu, tetapi sederhana dan saya hanya membutuhkannya. Mungkin menghemat orang lain 30 detik.


0

Masalah saya hampir mirip. Saya memiliki file yang tidak berkomitmen sebelum saya masuk git reset --hard.

Untungnya Saya berhasil melewati semua sumber daya ini. Setelah saya perhatikan bahwa saya bisa membatalkan ( ctrl-z). 😊 Saya hanya ingin menambahkan ini ke semua jawaban di atas.

Catatan. Tidak mungkin untuk ctrl-zmembuka file.


0

Ini telah menyelamatkan hidup saya: https://medium.com/@CarrieGuss/how-to-recover-from-a-git-hard-reset-b830b5e3f60c

Pada dasarnya Anda perlu menjalankan:

for blob in $(git fsck --lost-found | awk ‘$2 == “blob” { print $3 }’); do git cat-file -p $blob > $blob.txt; done

Kemudian secara manual melalui rasa sakit untuk mengatur ulang file Anda ke struktur yang benar.

Takeaway: Jangan pernah gunakan git reset --hardjika Anda tidak sepenuhnya 100% mengerti cara kerjanya, lebih baik tidak menggunakannya.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.