Dapatkah saya menghapus komit git tetapi menyimpan perubahan

1057

Di salah satu cabang pengembangan saya, saya membuat beberapa perubahan pada basis kode saya. Sebelum saya dapat menyelesaikan fitur yang sedang saya kerjakan, saya harus mengganti cabang saya saat ini menjadi master untuk mendemokan beberapa fitur. Tetapi hanya dengan menggunakan "master checkout git" mempertahankan perubahan yang saya buat di cabang pengembangan saya, sehingga merusak beberapa fungsi dalam master. Jadi yang saya lakukan adalah mengkomit perubahan pada cabang pengembangan saya dengan pesan komit "komit sementara" dan kemudian checkout master untuk demo.

Sekarang saya sudah selesai dengan demo dan kembali bekerja di cabang pengembangan saya, saya ingin menghapus "komitmen sementara" yang saya buat sambil tetap mempertahankan perubahan yang saya buat. Apakah itu mungkin?

tanookiben
sumber
65
Waktu berikutnya:git stash
Matt Ball
51
@ MatBall, tidak harus. Meskipun git stashmerupakan alat yang bagus, komit dibuang "work in progress" juga cukup sah.
kostix
3
Ini adalah selat sumber daya yang hebat dari Github: Cara membatalkan (hampir) apa pun dengan Git
jasonleonhard
9
@MattBall @kostix Ya, simpanan sangat tidak cocok untuk simpanan "jangka panjang", mengingat itu adalah satu tumpukan global untuk seluruh repo. Saya ingin dapat menyimpan perubahan pada cabang dan kemudian pergi ke cabang lain, melakukan apa pun, kembali beberapa hari kemudian tanpa khawatir bahwa saya mungkin telah menggunakan git stashbeberapa cabang lain untuk sementara.
Alec
4
Satu hal yang perlu diperhatikan stashadalah bahwa itu sepenuhnya lokal dan akan rentan terhadap kehilangan kode dari repo-penghapusan atau rekreasi atau, kegagalan atau kehilangan perangkat keras. IMO, itu benar-benar harus digunakan hanya untuk WIP jangka pendek. Suka komit WIP sebelum pergi berlibur: P .. anggap saja komit dump otak!
ϹοδεMεδιϲ

Jawaban:

1620

Sesederhana ini:

git reset HEAD^

Catatan: beberapa shell memperlakukan ^sebagai karakter khusus (misalnya beberapa shell Windows atau ZSH dengan globbing diaktifkan ), jadi Anda mungkin harus mengutip "HEAD^"dalam kasus tersebut.

git resettanpa --hardatau --softmemindahkan Anda HEADke komit yang ditentukan, tanpa mengubah file apa pun. HEAD^mengacu pada komit (pertama) dari komit Anda saat ini, yang dalam kasus Anda adalah komit sebelum komit sementara.

Perhatikan bahwa opsi lain dijalankan seperti biasa, dan kemudian pada komit berikutnya, jalankan:

git commit --amend [-m … etc]

yang sebaliknya akan mengedit komit terbaru, memiliki efek yang sama seperti di atas.

Perhatikan bahwa ini (seperti pada hampir setiap jawaban git) dapat menyebabkan masalah jika Anda telah mendorong komit buruk ke tempat di mana orang lain mungkin menariknya. Cobalah untuk menghindarinya

Gareth
sumber
47
Sejauh ini ini adalah yang paling sederhana, tetapi jika Anda sudah mendorong komit Anda ke remote dan orang lain menariknya, saya akan sangat ragu untuk melakukan apa pun kecuali meminta maaf.
atw13
11
@sicophrenic, jangan lewatkan kesempatan untuk membaca "Reset Demystified" pada kesempatan ini.
kostix
33
Saya dapatkan More?setelah melakukan ini. Apa pun yang saya ketik pada prompt itu memberi sayafatal: ambiguous argument 'HEADwhateverItypedIn': unknown revision or path not in the working tree.
DaAwesomeP
50
@DaAwesomeP terdengar seperti Anda menggunakan shell yang memperlakukan ^sebagai karakter khusus. Anda juga bisa mengutip referensi "HEAD^", atau menggunakan sintaks alternatif HEAD~1kuotasi
Gareth
8
Bekerja untuk saya, harus melarikan diri karaktergit reset HEAD\^
cevaris
188

Ada dua cara untuk menangani ini. Yang lebih mudah tergantung pada situasi Anda

Setel ulang

Jika komit yang ingin Anda singkirkan adalah komit terakhir, dan Anda belum melakukan pekerjaan tambahan yang bisa Anda gunakan git-reset

git reset HEAD^

Membawa cabang Anda kembali ke komit tepat sebelum KEPALA Anda saat ini. Namun, itu sebenarnya tidak mengubah file di pohon kerja Anda. Akibatnya, perubahan yang ada di komit itu muncul sebagai dimodifikasi - itu seperti perintah 'tidak berkomitmen'. Sebenarnya, saya punya alias untuk melakukan hal itu.

git config --global alias.uncommit 'reset HEAD^'

Maka Anda hanya dapat digunakan git uncommitdi masa depan untuk mencadangkan satu komit.

Squashing

Memencet komit berarti menggabungkan dua atau lebih komit menjadi satu. Saya cukup sering melakukan ini. Dalam kasus Anda, Anda memiliki setengah fitur yang dikomit, dan kemudian Anda akan menyelesaikannya dan melakukan lagi dengan pesan komit permanen yang tepat.

git rebase -i <ref>

Saya katakan di atas karena saya ingin memperjelas ini bisa menjadi jumlah komit kembali. Jalankan git logdan temukan komit yang ingin Anda singkirkan, salin SHA1-nya dan gunakan sebagai ganti <ref>. Git akan membawa Anda ke mode rebase interaktif. Ini akan menunjukkan semua komitmen antara keadaan Anda saat ini dan apa pun yang Anda lakukan <ref>. Jadi jika <ref>10 komit yang lalu, itu akan menampilkan 10 komit.

Di depan setiap komit, akan ada kata pick. Temukan komit yang ingin Anda singkirkan dan ubah dari pickmenjadi fixupatau squash. Menggunakan fixuphanya discards yang melakukan pesan dan menggabungkan perubahan ke pendahulunya langsung dalam daftar. Kata squashkunci melakukan hal yang sama, tetapi memungkinkan Anda untuk mengedit pesan komit dari komit baru digabungkan.

Perhatikan bahwa komit akan dikomit ulang sesuai urutan yang ditampilkan pada daftar saat Anda keluar dari editor. Jadi jika Anda membuat komit sementara, maka lakukan pekerjaan lain di cabang yang sama, dan selesaikan fitur di komit kemudian, kemudian menggunakan rebase akan memungkinkan Anda untuk mengurutkan ulang komit dan menghancurkannya.

PERINGATAN:

Rebasing memodifikasi riwayat - JANGAN lakukan ini pada komit yang telah Anda bagikan dengan pengembang lain.

Stashing

Di masa depan, untuk menghindari masalah ini pertimbangkan git stashuntuk menyimpan sementara pekerjaan yang tidak dikomit.

git stash save 'some message'

Ini akan menyimpan perubahan Anda saat ini ke sisi dalam daftar simpanan Anda. Di atas adalah versi yang paling eksplisit dari perintah simpanan, memungkinkan komentar untuk menggambarkan apa yang Anda simpan. Anda juga dapat menjalankan git stashdan tidak ada yang lain, tetapi tidak ada pesan yang akan disimpan.

Anda dapat menelusuri daftar simpanan Anda dengan ...

git stash list

Ini akan menunjukkan kepada Anda semua simpanan Anda, cabang apa yang telah mereka lakukan, dan pesan dan di awal setiap baris, dan pengidentifikasi untuk simpanan yang terlihat seperti ini di stash@{#}mana # adalah posisinya dalam susunan simpanan .

Untuk mengembalikan simpanan (yang dapat dilakukan pada cabang apa pun, terlepas dari tempat simpanan awalnya dibuat) Anda cukup menjalankan ...

git stash apply stash@{#}

Sekali lagi, ada posisi # dalam susunan simpanan. Jika simpanan yang ingin Anda pulihkan ada di 0posisi - yaitu, jika simpanan terbaru. Maka Anda hanya dapat menjalankan perintah tanpa menentukan posisi simpanan, git akan menganggap Anda berarti yang terakhir: git stash apply.

Jadi, misalnya, jika saya menemukan diri saya bekerja di cabang yang salah - saya dapat menjalankan urutan perintah berikut.

git stash
git checkout <correct_branch>
git stash apply

Dalam kasus Anda, Anda bergerak sedikit lebih banyak, tetapi ide yang sama masih berlaku.

Semoga ini membantu.

eddiemoya
sumber
6
git config --global alias.uncommit reset HEAD^hanya alias tidak berkomitmen untuk mengatur ulang. Sebagai gantinya, lakukangit config --global alias.uncommit 'reset HEAD^'
pertama
3
Perhatikan bahwa Anda harus menggunakan ^^ daripada ^ jika menggunakan di command prompt windows.
Pramod BR
106

Saya pikir Anda sedang mencari ini

git reset --soft HEAD~1

Ini membatalkan komitmen terbaru sementara menjaga perubahan yang dibuat dalam komitmen tersebut untuk pementasan.

Sudhanshu Jain
sumber
7
Terima kasih. Ini berhasil untuk saya. Memanggil git reset HEAD^Windows hanya meminta "Lebih banyak?" - apa pun artinya itu
Tyron
12
@ Tyron ^adalah karakter pelarian dalam DOS. Ketika dipasangkan dengan baris baru, ini berfungsi sebagai prompt lanjutan untuk perintah sebelumnya. Pengetikan git reset HEAD^^harus bekerja pada Windows.
trk
40

Ya, Anda dapat menghapus komit Anda tanpa menghapus perubahan: git reset @ ~

DURGESH
sumber
7
Ini benar-benar yang saya inginkan, dan itu akan menjadi jawaban yang diterima menurut pendapat saya, terima kasih banyak!
Carlos Liu
2
Menarik, sintaksis yang ringkas, saya belum pernah melihat atau menggunakannya sebelumnya. Bagaimana itu berbeda dari git reset --softatau git reset --keep?
user776686
18

Anda sedang mencari salah satu git reset HEAD^ --softatau git reset HEAD^ --mixed.

Ada 3 mode untuk perintah reset seperti yang dinyatakan dalam dokumen :

git reset HEAD^ --soft

batalkan git commit. Perubahan masih ada di pohon kerja (folder proyek) + indeks (--cached)

git reset HEAD^ --mixed

batalkan git commit+ git add. Perubahan masih ada di pohon kerja

git reset HEAD^ --hard

Sepertinya Anda tidak pernah melakukan perubahan pada basis kode. Perubahan hilang dari pohon kerja.

Bar Horing
sumber
9

Bagi yang menggunakan zsh, Anda harus menggunakan yang berikut:

git reset --soft HEAD\^

Dijelaskan di sini: https://github.com/robbyrussell/oh-my-zsh/issues/449

Jika URL menjadi mati, bagian yang penting adalah:

Lari ^ dalam perintah Anda

Anda juga dapat menggunakan KEPALA ~ sehingga Anda tidak perlu menghindarinya setiap kali.

Greg Hilston
sumber
15
Saya tidak pernah dapat mengingat perintah ini dan harus mencari di google ini dan menemukan jawaban saya sendiri hahahaha
Greg Hilston
2
git reset HEAD^bekerja di zsh untuk saya, mungkin sudah diperbaiki.
Ben Kolya Mansley
@ BenKolyaMansley Zsh versi apa yang Anda jalankan?
Greg Hilston
Saya menggunakanzsh 5.3 (x86_64-apple-darwin18.0)
Ben Kolya Mansley
7

Dalam kasus saya, saya sudah mendorong ke repo. Aduh!

Anda dapat mengembalikan komit tertentu sambil menyimpan perubahan di file lokal Anda dengan melakukan:

git revert -n <sha>

Dengan cara ini saya dapat menyimpan perubahan yang saya butuhkan dan membatalkan komitmen yang sudah didorong.

Wim Feijen
sumber
Dalam kasus saya, saya perlu mengembalikan sesuatu yang sudah saya dorong ke repositori jarak jauh. Bahkan lebih aduh! Cara terbaik adalah git revert bad-commit-sha, git revert -n revert-commit-just-created-shakemudian memperbaiki dari sana. Anda membuat saya setengah jalan. Terima kasih!
TinkerTenorSoftwareGuy
Ini tampaknya melakukan yang sebaliknya, bukan? Itu menciptakan perubahan baru yang sesuai dengan pengembalian perubahan yang dilakukan dalam komit terpilih. Jika Anda melakukan perubahan baru ini, Anda akan membatalkan pekerjaan yang sebenarnya ingin Anda pertahankan.
svaens
3

Menggunakan git 2.9 (tepatnya 2.9.2.windows.1) git reset HEAD^meminta lebih banyak; tidak yakin apa yang diharapkan dari input di sini. Silakan lihat screenshot di bawah ini

masukkan deskripsi gambar di sini

Temukan solusi lain git reset HEAD~#numberOfCommitsyang dapat kami pilih untuk memilih jumlah komit lokal yang ingin Anda setel ulang dengan mempertahankan perubahan Anda. Oleh karena itu, kami mendapat peluang untuk membuang semua komitmen lokal serta jumlah komitmen lokal yang terbatas.

Lihat screenshot di bawah ini yang ditampilkan git reset HEAD~1dalam aksi: masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

nkharche
sumber
Anda mungkin harus keluar dari karakter ^ - coba git reset "HEAD ^" atau git reset HEAD \ ^
Mark Fisher
Menambah ini, git reset HEAD ^^ bekerja sebagai tunggal ^ diperlakukan sebagai baris baru.
John Oss
2

Satu lagi cara untuk melakukannya.

Tambahkan komit di atas komit sementara dan kemudian lakukan:

git rebase -i

Untuk menggabungkan dua komit menjadi satu (perintah akan membuka file teks dengan instruksi eksplisit, edit).

Ruslan Osipov
sumber
2
Secara teknis benar tetapi jauh dari anggun seperti hanya melakukan git reset HEAD^. Git rebase memiliki banyak ruang untuk kesalahan di sini.
TheBuzzSaw
0

2020 Cara sederhana:

git reset <commit_hash>

(Hash komit dari komit terakhir yang ingin Anda pertahankan).

Jika komit didorong, Anda dapat melakukan:

git push -f

Anda akan menyimpan perubahan yang sekarang tidak dikomit secara lokal

Xys
sumber