Cara membatalkan "git commit --amend" dilakukan alih-alih "git commit"

1295

Saya tidak sengaja mengubah komit saya sebelumnya. Komit seharusnya terpisah untuk menjaga riwayat perubahan yang saya buat pada file tertentu.

Apakah ada cara untuk membatalkan komit terakhir? Jika saya melakukan sesuatu seperti git reset --hard HEAD^, komit pertama juga dibatalkan.

(Saya belum mendorong ke direktori remote)

Jesper Rønn-Jensen
sumber

Jawaban:

2291

Yang perlu Anda lakukan adalah membuat komit baru dengan detail yang sama dengan HEADkomit saat ini , tetapi dengan induk sebagai versi sebelumnya HEAD. git reset --softakan memindahkan pointer cabang sehingga komit berikutnya terjadi di atas komit yang berbeda dari tempat kepala cabang saat ini sekarang.

# Move the current head so that it's pointing at the old commit
# Leave the index intact for redoing the commit.
# HEAD@{1} gives you "the commit that HEAD pointed at before 
# it was moved to where it currently points at". Note that this is
# different from HEAD~1, which gives you "the commit that is the
# parent node of the commit that HEAD is currently pointing to."
git reset --soft HEAD@{1}

# commit the current tree using the commit details of the previous
# HEAD commit. (Note that HEAD@{1} is pointing somewhere different from the
# previous command. It's now pointing at the erroneously amended commit.)
git commit -C HEAD@{1}
CB Bailey
sumber
33
Sangat keren, +1. Saya bahkan melakukannya dengan amandemen kedua terakhir git refloguntuk mencari angka yang benar, misalnya {2}.
JJD
179
Supaya jelas, perintah pertama adalah "undo" yang benar. Ini menghasilkan KEPALA, direktori kerja (tidak berubah), dan status indeks sebelum git commit --amend. Yang ke-2 adalah "redo" menjadi komit baru. Ini bekerja untuk apa pun git commit, bukan hanya --amend.
cdunn2001
60
Jadi, jika Anda tidak mengubah dengan pesan komit baru yang perlu Anda selamatkan, bagian kedua bisa menjadi biasa git commit.
Matt Montag
18
Untuk beberapa alasan, saya mendapatkan error ketika menjalankan git reset --soft HEAD@{1}: fatal: ambiguous argument 'HEAD@1': unknown revision or path not in the working tree. Use '--' to separate paths from revisions. Ketika saya diganti HEAD@{1}dengan hash komit yang ditunjukkan pada git reflog(terima kasih JJD!), Jawaban ini bekerja dengan sangat baik!
Tim Camber
20
@TimArnold tergantung pada shell Anda, Anda mungkin perlu memberikan tanda kutip tunggal atau ganda HEAD@{1}. Jika saya menjalankan echo HEAD@{1}tcsh misalnya, outputnya adalah HEAD@1karena kawat gigi ditafsirkan oleh tcsh. Jika saya menggunakan tanda kutip tunggal, kawat gigi akan dipertahankan.
Kelvin
136

gunakan ref-log :

git branch fixing-things HEAD@{1}
git reset fixing-things

Anda kemudian harus memiliki semua perubahan yang diubah sebelumnya hanya di copy pekerjaan Anda dan dapat melakukan lagi

untuk melihat daftar lengkap dari tipe indeks sebelumnya git reflog

rajutan
sumber
7
Ini menghapus indeks juga - masih berguna, tetapi melampaui "undo" sederhana.
cdunn2001
3
apakah ada perbedaan antara HEAD@{1}dan HEAD~1?
neaumusic
15
@neaumusic: ya! HEAD~1persis sama dengan HEAD^dan mengidentifikasi induk dari komit saat ini. HEAD@{1}di sisi lain mengacu pada komit yang ditunjuk KEPALA sebelum ini, yaitu komit berarti berbeda ketika Anda checkout cabang yang berbeda atau mengubah komit.
Knittl
@knittl ah tidak heran saya tidak berpikir ini mungkin sebelumnya, terima kasih lagi, informasi yang baik
neaumusic
9
langkah pertama adalah mubazir. Sederhana git reset HEAD@{1}sudah cukup.
dwelle
79

Temukan komitmen yang diubah oleh:

git log --reflog

Catatan: Anda dapat menambahkan --patchuntuk melihat tubuh komit untuk kejelasan. Sama dengangit reflog .

kemudian atur ulang KEPALA Anda ke komit sebelumnya pada saat itu baik-baik saja dengan:

git reset SHA1 --hard

Catatan: Ganti SHA1 dengan hash komit asli Anda. Perhatikan juga bahwa perintah ini akan kehilangan perubahan yang tidak dikomit, jadi Anda dapat menyimpannya sebelumnya. Sebagai alternatif, gunakan --softsebagai gantinya untuk menyimpan perubahan terbaru dan kemudian lakukan.

Kemudian pilih cherry yang lain yang Anda butuhkan di atasnya:

git cherry-pick SHA1
kenorb
sumber
26
Jika ya git reset SHA1 --soft, Anda dapat menyimpan perubahan terbaru dan kemudian mengkomitnya.
pravj
24

Anda selalu dapat membagi komit, Dari manual

  • Mulai rebase interaktif dengan git rebase -i commit ^, di mana komit adalah komit yang ingin Anda bagi. Faktanya, rentang komit apa pun akan dilakukan, asalkan berisi komit itu.
  • Tandai komit yang ingin Anda bagi dengan tindakan "edit".
  • Ketika perlu mengedit komit itu, jalankan git reset HEAD ^. Efeknya adalah bahwa KEPALA digulung ulang oleh satu, dan indeks mengikuti. Namun, pohon yang bekerja tetap sama.
  • Sekarang tambahkan perubahan ke indeks yang ingin Anda miliki di komit pertama. Anda dapat menggunakan git add (mungkin secara interaktif) atau git-gui (atau keduanya) untuk melakukan itu.
  • Komit indeks sekarang-saat ini dengan pesan komit apa pun yang sesuai sekarang.
  • Ulangi dua langkah terakhir hingga pohon kerja Anda bersih.
  • Lanjutkan rebase dengan git rebase --continue.
Arkaitz Jimenez
sumber
26
terlalu rumit. git reflogadalah yang Anda butuhkan
knittl
2
Banyak langkah ya, tetapi setiap langkah tidak rumit dan mudah dilakukan. Ini bekerja untuk saya dan mendapatkan suara saya.
OzBandit
5
selain itu, jawaban ini memungkinkan Anda untuk memilih secara selektif perubahan yang secara tidak sengaja 'diubah', untuk memberikan beberapa nilai tambahan pada git reset --soft HEAD @ {1} pendekatan (yang memang memecahkan masalah saya BTW)
Wiebe Tijsma
2
Anda juga dapat memilih perubahan dengan metode reflog secara selektif. Lakukan saja git resetalih - alih git reset --soft, lalu lakukan git add --patch.
geekofalltrades
1
Ini masih menulis ulang sejarah dan membutuhkan dorongan gaya. Tergantung pada situasi Anda yang mungkin atau mungkin tidak menjadi masalah.
Pajn
20

Mungkin perlu dicatat bahwa jika Anda masih di editor Anda dengan pesan komit, Anda dapat menghapus pesan komit dan itu akan membatalkan git commit --amendperintah.

Justin Schulz
sumber
Ini adalah salah satunya.
atilkan
Menyelamatkan saya tetapi ^^
engineercoding
14

Mungkin bisa digunakan git reflog untuk mendapatkan dua komit sebelum mengubah dan setelah mengubah.

Kemudian gunakan git diff before_commit_id after_commit_id > d.diff untuk mendapatkan perbedaan antara sebelum mengubah dan setelah mengubah.

Penggunaan selanjutnya git checkout before_commit_id untuk kembali sebelum komit

Dan penggunaan terakhir git apply d.diff untuk menerapkan perubahan nyata yang Anda lakukan.

Itu memecahkan masalah saya.

utzcoz
sumber
11

Jika Anda telah mendorong komit ke remote dan kemudian salah mengubah perubahan pada komit ini, ini akan memperbaiki masalah Anda. Masalah a git loguntuk menemukan SHA sebelum komit. (ini menganggap remote bernama asal). Sekarang keluarkan perintah ini menggunakan SHA itu.

git reset --soft <SHA BEFORE THE AMMEND>
#you now see all the changes in the commit and the amend undone

#save ALL the changes to the stash
git stash

git pull origin <your-branch> --ff-only
#if you issue git log you can see that you have the commit you didn't want to amend

git stash pop
#git status reveals only the changes you incorrectly amended

#now you can create your new unamended commit
David Sopko
sumber
3
Ini adalah kasus khusus dari pertanyaan yang lebih umum, tetapi itu mencakup kebutuhan saya yang mendesak.
dmckee --- ex-moderator kitten
8

Anda dapat melakukan di bawah ini untuk membatalkan git commit —amend

  1. git reset --soft HEAD^
  2. git checkout files_from_old_commit_on_branch
  3. git pull origin your_branch_name

====================================

Sekarang perubahan Anda seperti sebelumnya. Jadi, Anda sudah selesai dengan undo untukgit commit —amend

Sekarang Anda bisa melakukannya git push origin <your_branch_name>, untuk mendorong ke cabang.

Pratik
sumber
3

Hampir 9 tahun terlambat untuk ini tetapi tidak melihat variasi ini disebutkan menyelesaikan hal yang sama (ini semacam kombinasi dari beberapa di antaranya, mirip dengan jawaban teratas ( https://stackoverflow.com/a/1459264/4642530 ) .

Cari semua kepala terpisah di cabang

git reflog show origin/BRANCH_NAME --date=relative

Kemudian temukan hash SHA1

Setel ulang ke SHA1 lama

git reset --hard SHA1

Kemudian dorong kembali.

git push origin BRANCH_NAME

Selesai

Ini akan mengembalikan Anda sepenuhnya ke komitmen lama.

(Termasuk tanggal komit terlepas sebelumnya yang ditimpa sebelumnya)

garrettmac
sumber
Ya, tapi saya biasanya ingin mengatur ulang --softuntuk menjaga perubahan saya. Saya hanya ingin itu dilakukan secara terpisah
Juan Mendes
2
  1. Checkout ke cabang sementara dengan komit terakhir

    git branch temp HEAD@{1}

  2. Setel ulang komit terakhir

    git reset temp

  3. Sekarang, Anda akan memiliki semua file komit Anda dan juga komit sebelumnya. Periksa status semua file.

    git status

  4. Setel ulang file komit Anda dari tahap git.

    git reset myfile1.js (seterusnya)

  5. Pasang kembali komit ini

    git commit -C HEAD@{1}

  6. Tambahkan dan komit file Anda ke komit baru.

Priyanshu Chauhan
sumber