Dalam bahasa Inggris biasa, apa yang dilakukan “git reset”?

674

Saya telah melihat posting menarik yang menjelaskan tentang seluk-beluk git reset.

Sayangnya, semakin saya membaca tentang hal itu, semakin saya tidak mengerti sepenuhnya. Saya berasal dari latar belakang SVN dan Git adalah paradigma baru. Saya mudah lincah, tetapi Git jauh lebih teknis.

Saya pikir git resetdekat hg revert, tetapi tampaknya ada perbedaan.

Jadi apa yang sebenarnya git resetdilakukan? Harap sertakan penjelasan terperinci tentang:

  • opsi --hard, --softdan --merge;
  • notasi aneh yang Anda gunakan dengan HEADseperti HEAD^dan HEAD~1;
  • kasus penggunaan konkret dan alur kerja;
  • konsekuensi pada copy pekerjaan, HEADdan tingkat stres global Anda.
e-satis
sumber
17
Saya pikir A Referensi Visual Git memberikan wawasan yang baik tentang apa yang terjadi ketika menggunakan perintah git umum.

Jawaban:

992

Secara umum, git resetfungsi adalah untuk mengambil cabang saat ini dan mengatur ulang untuk menunjuk ke tempat lain, dan mungkin membawa indeks dan pohon kerja. Lebih konkretnya, jika cabang utama Anda (saat ini check out) adalah seperti ini:

- A - B - C (HEAD, master)

dan Anda menyadari bahwa Anda ingin master menunjuk ke B, bukan C, Anda akan menggunakannya git reset Buntuk memindahkannya ke sana:

- A - B (HEAD, master)      # - C is still here, but there's no branch pointing to it anymore

Digresi: Ini berbeda dari checkout. Jika Anda menjalankan git checkout B, Anda akan mendapatkan ini:

- A - B (HEAD) - C (master)

Anda berakhir dalam keadaan KEPALA terpisah. HEAD, pohon kerja, indeks semua cocok B, tetapi cabang master tertinggal di C. Jika Anda membuat komit baru Dpada titik ini, Anda akan mendapatkan ini, yang mungkin bukan yang Anda inginkan:

- A - B - C (master)
       \
        D (HEAD)

Ingat, reset tidak membuat komit, itu hanya memperbarui cabang (yang merupakan pointer ke komit) untuk menunjuk ke komit yang berbeda. Sisanya hanyalah detail dari apa yang terjadi pada indeks dan pohon kerja Anda.

Gunakan kasing

Saya membahas banyak kasus penggunaan utama git resetdalam deskripsi saya tentang berbagai opsi di bagian selanjutnya. Ini benar-benar dapat digunakan untuk berbagai hal; benang merahnya adalah bahwa semuanya melibatkan pengaturan ulang cabang, indeks, dan / atau pohon kerja untuk menunjuk / cocok dengan komit yang diberikan.

Hal-hal yang harus diperhatikan

  • --harddapat menyebabkan Anda benar-benar kehilangan pekerjaan. Ini memodifikasi pohon kerja Anda.

  • git reset [options] commitdapat menyebabkan Anda (semacam) kehilangan komitmen. Dalam contoh mainan di atas, kami kehilangan komit C. Itu masih dalam repo, dan Anda dapat menemukannya dengan melihat git reflog show HEADatau git reflog show master, tetapi sebenarnya tidak dapat diakses dari cabang apa pun lagi.

  • Git menghapus komit seperti itu secara permanen setelah 30 hari, tetapi sampai saat itu Anda dapat memulihkan C dengan menunjuk cabang itu lagi ( git checkout C; git branch <new branch name>).

Argumen

Mengutip halaman manual, penggunaan yang paling umum adalah dari formulir git reset [<commit>] [paths...], yang akan mengatur ulang jalur yang diberikan ke negara mereka dari komit yang diberikan. Jika jalur tidak disediakan, seluruh hierarki diatur ulang, dan jika komit tidak disediakan, maka akan dianggap HEAD (komit saat ini). Ini adalah pola umum di seluruh perintah git (misalnya checkout, diff, log, meskipun semantik yang tepat berbeda), jadi seharusnya tidak terlalu mengejutkan.

Sebagai contoh, git reset other-branch path/to/foome-reset semua yang ada di path / ke / foo ke statusnya di cabang-lain, git reset -- .me-reset direktori saat ini ke statusnya di HEAD, dan yang sederhana git resetme-reset semuanya ke state-nya di HEAD.

Opsi pohon pekerjaan dan indeks utama

Ada empat opsi utama untuk mengontrol apa yang terjadi pada pohon kerja Anda dan indeks selama reset.

Ingat, indeks adalah "area pementasan" git - di situlah segalanya berjalan ketika Anda mengatakan git adddalam persiapan untuk berkomitmen.

  • --hardmembuat semuanya sesuai dengan komit yang telah Anda atur ulang. Mungkin ini yang paling mudah dipahami. Semua perubahan lokal Anda akan musnah. Salah satu penggunaan utama adalah membuang pekerjaan Anda tetapi tidak beralih komit: git reset --hardberarti git reset --hard HEAD, yaitu jangan mengubah cabang tetapi singkirkan semua perubahan lokal. Yang lain hanya memindahkan cabang dari satu tempat ke tempat lain, dan menjaga pohon indeks / kerja tetap sinkron. Ini adalah salah satu yang benar-benar dapat membuat Anda kehilangan pekerjaan, karena itu memodifikasi pohon pekerjaan Anda. Pastikan Anda ingin membuang pekerjaan lokal sebelum menjalankannya reset --hard.

  • --mixedadalah default, yaitu git resetberarti git reset --mixed. Ini me-reset indeks, tetapi bukan pohon kerja. Ini berarti semua file Anda utuh, tetapi setiap perbedaan antara komit asli dan yang Anda setel ulang akan muncul sebagai modifikasi lokal (atau file yang tidak dilacak) dengan status git. Gunakan ini ketika Anda menyadari bahwa Anda melakukan beberapa komitmen buruk, tetapi Anda ingin mempertahankan semua pekerjaan yang telah Anda lakukan sehingga Anda dapat memperbaikinya dan berkomitmen kembali. Untuk melakukan komitmen, Anda harus menambahkan file ke indeks lagi ( git add ...).

  • --softtidak menyentuh indeks atau pohon kerja. Semua file Anda masih utuh dengan --mixed, tetapi semua perubahan muncul changes to be committeddengan status git (mis. Diperiksa saat persiapan untuk melakukan). Gunakan ini ketika Anda menyadari bahwa Anda telah melakukan beberapa komitmen buruk, tetapi pekerjaan itu baik - semua yang perlu Anda lakukan adalah komitmen ulang secara berbeda. Indeks tidak tersentuh, sehingga Anda dapat mengkomit segera jika Anda mau - komit yang dihasilkan akan memiliki semua konten yang sama dengan di mana Anda berada sebelum Anda mengatur ulang.

  • --mergeditambahkan baru-baru ini, dan dimaksudkan untuk membantu Anda membatalkan penggabungan yang gagal. Ini diperlukan karena git mergeakan benar-benar membiarkan Anda mencoba penggabungan dengan pohon kerja kotor (satu dengan modifikasi lokal) selama modifikasi tersebut ada di file yang tidak terpengaruh oleh penggabungan. git reset --mergeme-reset indeks (seperti --mixed- semua perubahan muncul sebagai modifikasi lokal), dan me-reset file yang terpengaruh oleh penggabungan, tetapi membiarkan yang lain sendirian. Mudah-mudahan ini akan mengembalikan semuanya ke keadaan sebelum penggabungan yang buruk. Anda biasanya akan menggunakannya sebagai git reset --merge(artinya git reset --merge HEAD) karena Anda hanya ingin mengatur ulang penggabungan, tidak benar-benar memindahkan cabang. ( HEADbelum diperbarui, karena penggabungan gagal)

    Agar lebih konkret, misalkan Anda telah memodifikasi file A dan B, dan Anda mencoba untuk menggabungkan cabang yang memodifikasi file C dan D. Penggabungan gagal karena beberapa alasan, dan Anda memutuskan untuk membatalkannya. Anda menggunakan git reset --merge. Ini membawa C dan D kembali ke bagaimana mereka berada HEAD, tetapi membiarkan modifikasi Anda untuk A dan B sendirian, karena mereka bukan bagian dari upaya penggabungan.

Ingin tahu lebih banyak?

Saya pikir man git resetini benar-benar bagus untuk ini - mungkin Anda perlu sedikit merasakan cara git bekerja agar mereka benar-benar tenggelam. Khususnya, jika Anda meluangkan waktu untuk membacanya dengan cermat, tabel-tabel yang merinci status file dalam indeks dan pohon kerja untuk semua berbagai opsi dan case sangat sangat membantu. (Tapi ya, mereka sangat padat - mereka menyampaikan banyak sekali informasi di atas dalam bentuk yang sangat ringkas.)

Notasi aneh

"Notasi aneh" ( HEAD^dan HEAD~1) yang Anda sebutkan hanyalah singkatan untuk menentukan komit, tanpa harus menggunakan nama hash seperti 3ebe3f6. Itu sepenuhnya didokumentasikan di bagian "menentukan revisi" dari halaman manual untuk git-rev-parse, dengan banyak contoh dan sintaks terkait. Tanda sisipan dan tilde sebenarnya memiliki arti berbeda :

  • HEAD~kependekan dari HEAD~1dan berarti orang tua pertama dari komit. HEAD~2berarti orang tua pertama dari orang tua komit. Pikirkan HEAD~nsebagai "n melakukan sebelum KEPALA" atau "leluhur generasi ke-8 KEPALA".
  • HEAD^(atau HEAD^1) juga berarti orang tua pertama dari komit. HEAD^2berarti induk kedua komit . Ingat, komit gabungan normal memiliki dua orang tua - orang tua pertama adalah komit gabungan, dan orangtua kedua adalah komit yang digabungkan. Secara umum, penggabungan sebenarnya dapat memiliki banyak orang tua secara sewenang-wenang (gurita bergabung).
  • The ^dan ~operator dapat dirangkai, seperti dalam HEAD~3^2, orang tua kedua dari nenek moyang generasi ketiga dari HEAD, HEAD^^2, induk kedua induk pertama HEAD, atau bahkan HEAD^^^, yang setara dengan HEAD~3.

caret dan tilde

Cascabel
sumber
"Anda akan menggunakan git reset untuk memindahkannya ke sana." mengapa Anda tidak menggunakan checkout git untuk melakukannya?
e-satis
5
@ e-satis: checkout git akan memindahkan HEAD, tetapi meninggalkan cabang di tempat itu. Ini untuk saat Anda ingin memindahkan cabang.
Cascabel
Jadi jika saya mengerti dengan baik, reset B akan melakukan: - A - B - C - B (master) sementara checkout B akan dilakukan - A - B (master)?
e-satis
32
dokumen-dokumen itu bagus meskipun butuh waktu lama untuk membacanya dan mereka sangat padat dan perlu selamanya untuk memverifikasi bahwa mereka mengatakan itu berfungsi seperti Anda sudah tahu cara kerjanya. Tidak terdengar seperti dokumen itu baik bagiku ...
Kirby
4
Penjelasan yang lebih sederhana dan dapat dimengerti diberikan oleh jawaban SO ini: stackoverflow.com/questions/3528245/whats-the-difference-between-git-reset-mixed-soft-and-hard
Nitin Bansal
80

Ingatlah bahwa di dalam gitkamu ada:

  • yang HEADpointer , yang memberitahu Anda apa yang berkomitmen sedang Anda kerjakan
  • yang pohon kerja , yang mewakili negara bagian file pada sistem Anda
  • yang area stage (juga disebut indeks ), yang "tahap" perubahan sehingga mereka nantinya bisa dilakukan bersama-sama

Harap sertakan penjelasan terperinci tentang:

--hard, --softdan --merge;

Dalam meningkatkan urutan bahaya:

  • --softbergerak HEADtetapi tidak menyentuh area pementasan atau pohon yang bekerja.
  • --mixedbergerak HEADdan memperbarui area pementasan, tetapi bukan pohon yang berfungsi.
  • --mergememindahkan HEAD, mengatur ulang area pementasan, dan mencoba untuk memindahkan semua perubahan di pohon kerja Anda ke pohon kerja baru.
  • --hardbergerak HEAD dan menyesuaikan area pementasan Anda dan pohon kerja ke yang baru HEAD, membuang semuanya.

kasus penggunaan konkret dan alur kerja;

  • Gunakan --softsaat Anda ingin pindah ke komit lain dan menambal sesuatu tanpa "kehilangan tempat Anda". Sangat jarang Anda membutuhkan ini.

-

# git reset --soft example
touch foo                            // Add a file, make some changes.
git add foo                          // 
git commit -m "bad commit message"   // Commit... D'oh, that was a mistake!
git reset --soft HEAD^               // Go back one commit and fix things.
git commit -m "good commit"          // There, now it's right.

-

  • Gunakan --mixed(yang merupakan default) ketika Anda ingin melihat hal-hal seperti apa di komit lain, tetapi Anda tidak ingin kehilangan perubahan yang sudah Anda miliki.

  • Gunakan --mergesaat Anda ingin pindah ke tempat baru tetapi sertakan perubahan yang sudah Anda miliki ke pohon kerja.

  • Gunakan --harduntuk menghapus semuanya dan memulai daftar baru di komit baru.

John Feminella
sumber
2
Itu bukan kasus penggunaan yang dimaksudkan untuk reset --merge. Itu tidak melakukan penggabungan tiga arah. Ini benar-benar hanya untuk mengatur ulang dari gabungan yang bertentangan, seperti yang dijelaskan dalam dokumen. Anda ingin menggunakannya checkout --mergeuntuk melakukan apa yang Anda bicarakan. Jika Anda ingin memindahkan cabang juga, saya pikir satu-satunya cara adalah menindaklanjuti checkout / reset untuk menyeretnya.
Cascabel
@Jefromi »Ya, saya tidak mengucapkannya dengan baik. Dengan "tempat baru" yang saya maksudkan adalah "tempat baru di mana Anda tidak memiliki penggabungan yang bertentangan".
John Feminella
1
Ah, begitu. Saya pikir yang penting di sini adalah bahwa kecuali Anda benar-benar tahu apa yang Anda lakukan, Anda mungkin tidak ingin menggunakan reset --mergetarget apa pun selain (default) HEAD, karena dalam kasus-kasus selain membatalkan penggabungan yang bertentangan, itu akan membuang informasi yang bisa Anda simpan.
Cascabel
2
Saya menemukan jawaban ini yang paling sederhana dan paling membantu
Jazzepi
Harap tambahkan informasi tentang perintah ini: git resetdan git reset -- ..
Flimm
35

Posting Reset Demystified di blog Pro Git memberikan penjelasan yang sangat cerdas tentang git resetdan git checkout.

Setelah semua diskusi bermanfaat di bagian atas posting itu, penulis mengurangi aturan menjadi tiga langkah sederhana berikut:

Itu pada dasarnya. The resetperintah menimpa tiga pohon ini dalam urutan tertentu, berhenti ketika Anda kirim ke.

  1. Pindahkan apa pun poin HEAD cabang (berhenti jika --soft)
  2. LALU, buat Indeks terlihat seperti itu (berhenti di sini kecuali --hard)
  3. MAKA, buat Direktori Kerja terlihat seperti itu

Ada juga --mergedan --keepopsi, tetapi saya lebih suka menjaga hal-hal sederhana untuk saat ini - itu akan menjadi artikel lain.

Daniel Hershcovich
sumber
25

Saat Anda melakukan sesuatu untuk git, pertama-tama Anda harus membuat (menambahkan indeks) perubahan Anda. Ini berarti Anda harus git menambahkan semua file yang ingin Anda sertakan dalam komit ini sebelum git menganggapnya sebagai bagian dari komit. Pertama mari kita melihat-lihat gambar repo git: masukkan deskripsi gambar di sini

jadi, itu sederhana sekarang. Kita harus bekerja di direktori kerja, membuat file, direktori, dan semua. Perubahan ini adalah perubahan yang tidak terlacak. Untuk membuatnya dilacak, kita perlu menambahkannya ke indeks git dengan menggunakan perintah git add . Setelah mereka ditambahkan ke indeks git. Kami sekarang dapat melakukan perubahan ini, jika kami ingin mendorongnya ke git repositori.

Tapi tiba-tiba kami mengetahui sementara berkomitmen bahwa kami memiliki satu file tambahan yang kami tambahkan dalam indeks tidak diperlukan untuk mendorong repositori git. Itu berarti kita tidak ingin file itu di indeks. Sekarang pertanyaannya adalah bagaimana cara menghapus file itu dari indeks git, Karena kita menggunakan git add untuk meletakkannya dalam indeks, apakah logis menggunakan git rm ? Salah! git rm hanya akan menghapus file dan menambahkan penghapusan ke indeks. Jadi apa yang harus dilakukan sekarang:

Menggunakan:-

git reset

Ini membersihkan indeks Anda, membuat direktori kerja Anda tidak tersentuh. (cukup unstaging semuanya).

Itu dapat digunakan dengan sejumlah opsi dengannya. Ada tiga opsi utama untuk digunakan dengan git reset: --hard, --soft dan --mixed . Ini memengaruhi apa yang direset di samping pointer HEAD saat Anda mengatur ulang.

Pertama, --hard me-reset segalanya. Direktori Anda saat ini akan persis sama jika Anda telah mengikuti cabang itu selama ini. Direktori kerja dan indeks diubah ke komit itu. Ini adalah versi yang paling sering saya gunakan. git reset --hard adalah sesuatu seperti svn revert .

Selanjutnya, kebalikan total, —soft , tidak mengatur ulang pohon kerja atau indeks. Ini hanya memindahkan pointer HEAD. Ini membuat kondisi Anda saat ini dengan perubahan yang berbeda dari komit yang Anda alihkan di direktori Anda, dan "dipentaskan" untuk melakukan. Jika Anda membuat komit secara lokal tetapi belum mendorong komit ke server git, Anda dapat mengatur ulang ke komit sebelumnya, dan komit kembali dengan pesan komit yang baik.

Akhirnya, --mixed me-reset indeks, tetapi bukan pohon yang berfungsi. Jadi semua perubahan masih ada, tetapi "tidak dipentaskan" dan perlu git add'ed atau git commit -a . kita menggunakan ini kadang-kadang jika kita melakukan lebih dari yang kita maksud dengan git commit -a, kita dapat mencadangkan komit dengan git reset --mixed, tambahkan hal-hal yang ingin kita komit dan hanya komit saja.

Perbedaan antara git revert dan git reset : -


Dengan kata sederhana, git reset adalah perintah untuk "memperbaiki kesalahan yang tidak dikomit" dan git revert adalah perintah untuk "memperbaiki kesalahan yang dilakukan" .

Itu berarti jika kita telah membuat beberapa kesalahan dalam beberapa perubahan dan melakukan dan mendorong hal yang sama ke git repo, maka git revert adalah solusinya. Dan jika seandainya kita telah mengidentifikasi kesalahan yang sama sebelum mendorong / melakukan, kita dapat menggunakan git reset untuk memperbaiki masalah.

Saya harap ini akan membantu Anda untuk menghilangkan kebingungan Anda.

cinta
sumber
2
Ini adalah jawaban bahasa Inggris sederhana yang bagus seperti yang diminta oleh OP.
Episodex
1
Meskipun saya mungkin melewatkan itu dalam jawaban Anda. Apa itu git reset HEADdefault? --hard, --softatau --mixed? Jawaban bagus btw.
giannis christofakis
1
Jawaban yang bagus, tetapi saya akan membuatnya lebih jelas yang git reset --hardakan menyebabkan Anda kehilangan beberapa data. Dan ada poin yang bisa salah (walaupun saya tidak 100% yakin ... Masih belajar!): Berbicara tentang --mixedAnda mengatakan bahwa "kita menggunakan ini kadang-kadang jika kita melakukan lebih dari yang kita maksudkan dengan git commit -a". Apakah maksud Anda: "jika kami melakukan lebih dari yang seharusnya git stage ."? Jika Anda benar-benar melakukannya, saya pikir sudah terlambat (seperti yang Anda katakan di akhir, git reset adalah perintah untuk "memperbaiki kesalahan yang tidak dikomit")
Fabio mengatakan Reinstate Monica
6

TL; DR

git resetme-reset Staging ke komit terakhir. Gunakan --hardjuga untuk mengatur ulang file di direktori Kerja Anda ke komit terakhir.

VERSI YANG LEBIH LAMA

Tapi itu jelas sederhana karena banyak jawaban yang agak bertele-tele. Lebih masuk akal bagi saya untuk membaca git resetdalam konteks membatalkan perubahan. Misalnya lihat ini:

Jika git revert adalah cara "aman" untuk membatalkan perubahan, Anda dapat menganggap git reset sebagai metode berbahaya. Ketika Anda membatalkan dengan git reset (dan komit tidak lagi dirujuk oleh ref atau reflog), tidak ada cara untuk mengambil salinan asli — itu adalah membatalkan permanen. Kehati-hatian harus diambil saat menggunakan alat ini, karena ini adalah satu-satunya perintah Git yang berpotensi kehilangan pekerjaan Anda.

Dari https://www.atlassian.com/git/tutorials/undoing-changes/git-reset

dan ini

Pada level komit, pengaturan ulang adalah cara untuk memindahkan ujung cabang ke komit yang berbeda. Ini dapat digunakan untuk menghapus komit dari cabang saat ini.

Dari https://www.atlassian.com/git/tutorials/resetting-checking-out-and-reverting/commit-level-operations

Snowcrash
sumber
2

Perlu diketahui, ini adalah penjelasan yang disederhanakan yang dimaksudkan sebagai langkah pertama untuk memahami fungsi yang rumit ini.

Semoga bermanfaat bagi pelajar visual yang ingin memvisualisasikan seperti apa keadaan proyek mereka setelah masing-masing perintah ini:


Bagi mereka yang menggunakan Terminal dengan warna dihidupkan (git config --global color.ui auto):

git reset --soft A dan Anda akan melihat barang B dan C berwarna hijau (dipentaskan dan siap untuk dikomit)

git reset --mixed A(atau git reset A) dan Anda akan melihat barang B dan C berwarna merah (tidak dipentaskan dan siap dipentaskan (hijau) dan kemudian dikomit)

git reset --hard A dan Anda tidak akan lagi melihat perubahan B dan C di mana saja (seolah-olah tidak pernah ada)


Atau bagi mereka yang menggunakan program GUI seperti 'Tower' atau 'SourceTree'

git reset --soft A dan Anda akan melihat barang B dan C di area 'file bertahap' siap untuk dikomit

git reset --mixed A(atau git reset A) dan Anda akan melihat barang-barang B dan C di area 'file tidak dipentaskan' siap dipindahkan ke panggung dan kemudian dilakukan

git reset --hard A dan Anda tidak akan lagi melihat perubahan B dan C di mana saja (seolah-olah tidak pernah ada)

timhc22
sumber
1

Checkout menunjuk kepala pada komit tertentu.

Setel ulang titik cabang pada komit tertentu. (Cabang adalah pointer ke komit.)

Kebetulan, jika kepala Anda tidak menunjuk ke sebuah komit yang juga ditunjuk oleh cabang maka Anda memiliki kepala yang terpisah. (Ternyata salah. Lihat komentar ...)

Ian Warburton
sumber
1
Bukan untuk nitpick, tapi (ya, sebenarnya itu adalah nitpicking tapi mari kita tambahkan saja) kalimat ketiga Anda secara teknis salah. Katakanlah KEPALA Anda menunjuk ke cabang B yang pada gilirannya menunjuk untuk melakukan abc123. Jika sekarang Anda checkout commit abc123, KEPALA dan cabang B Anda berdua menunjuk untuk melakukan abc123 DAN KEPALA Anda terlepas. Komitmen pada titik ini tidak akan memperbarui posisi cabang B. Anda bisa mengatakan "jika kepala Anda tidak mengarah ke cabang maka Anda memiliki kepala yang terpisah"
RomainValeri
@RomainValeri Apa yang akan dilakukan dalam keadaan itu?
Ian Warburton
1
Komit akan membuat komit yang tidak direferensikan oleh cabang mana pun, dan cabang B akan terus menunjuk ke komit yang sama abc123 bahkan setelah Anda komit berkali-kali setelah itu. Ini menyiratkan bahwa komit ini akan menjadi kandidat untuk pengumpulan sampah ketika HEAD berhenti menunjuk komit terakhir dalam serangkaian komit 'liar' ini.
RomainValeri