Paghahambing

git reset at git revert: paano i-undo ang commit nang hindi nasisira ang history

Na-update: · Skillaria.Top

Ginagalaw ng git reset ang pointer ng branch pabalik at isinusulat muli ang history, kaya para lang ito sa lokal at hindi pa naipapadalang commit. Gumagawa naman ang git revert ng bagong commit na nagbabaligtad ng pagbabago, nang hindi ginagalaw ang history, kaya ito ang ligtas na paraan para i-undo ang commit na nasa server na.

Sa madaling sabi: iniuurong ng git reset ang branch at kumikilos na parang walang sobrang commit. Iniiwan ng git revert ang history gaya ng dati at nagdadagdag ng bagong commit na nagbabaligtad sa mga pagbabago ng luma. Ang una ay para sa lokal na trabaho; ang ikalawa ay para sa lahat ng nakarating na sa shared repository. Kung ito lang ang tandaan ninyo, maiiwasan na ang karamihan ng aksidente sa Git.

Sa ibaba, tatalakayin kung paano gumagana ang dalawang command, ano ang pagkakaiba ng mga mode ng reset, paano i-undo ang commit pagkatapos ng push, paano ibalik ang "nawalang" commit, at ano ang kinalaman ng git clean.

Tatlong antas na nagbabago sa mga command ng pag-undo

Para maintindihan ang pagkakaiba, alalahanin ang tatlong bahagi ng Git: working directory (mga file sa disk), index (staging area, ang papasok sa susunod na commit), at history (mga commit na tinuturo ng branch at HEAD). May sariling hanay ng mga bahaging ito ang bawat command ng pag-undo.

CommandHistoryIndexWorking directoryLigtas para sa shared branch
git restore filehindihindioooo
git restore --staged filehindioohindioo
git reset --softoohindihindihindi
git reset --mixed (default)oooohindihindi
git reset --hardoooooohindi
git revertnagdaragdag ng commit——oo
git cleanhindihindibinubura ang mga hindi tinatrack na fileoo, pero hindi na maibabalik

Paano gumagana ang git reset

Inililipat ng git reset <commit> ang pointer ng kasalukuyang branch (at kasama nito ang HEAD) papunta sa tinukoy na commit. Hindi pisikal na nabubura ang mga commit na nasa "likod" nito, pero hindi na sila nakikita sa branch. Tinutukoy ng mode kung ano ang mangyayari sa index at mga file.

git reset --soft: i-undo ang commit, pero nasa index pa rin ang mga pagbabago

Nailipat ang branch, pero nananatili ang index at mga file gaya ng dati. Lahat ng pagbabago mula sa mga inatras na commit ay nakahanda na para sa commit. Ito ang perpektong paraan para palitan ang mensahe o pagsamahin ang ilang huling commit sa isa.

git reset --soft HEAD~3
git commit -m "feat: form ng registration"

Naging isang commit ang huling tatlong commit, at hindi nagbago ang nilalaman ng mga file.

git reset --mixed: i-undo ang commit at ang index

Ito ang default na mode: ang git reset HEAD~1 ay katumbas ng git reset --mixed HEAD~1. Nailipat ang branch, na-reset ang index, at nananatili ang mga pagbabago sa working directory bilang hindi pa nahahanda. Kapaki-pakinabang kapag may nakommit kayong hindi dapat, at gusto ninyong pag-isipang muli kung ano at sa anong bahagi idadagdag.

git reset HEAD~1
git status
# Changes not staged for commit:
#   modified:   app.py
#   modified:   config.yml

git reset --hard: ganap na rollback

Ang branch, index, at working directory ay ibabalik sa estado ng tinukoy na commit. Lahat ng hindi pa naka-commit na pagbabago sa mga tinatrack na file ay mawawala nang walang babala. Ito lang ang mode ng reset na talagang makakasira ng trabaho ninyo.

git reset --hard HEAD~1          # itapon ang huling commit at lahat ng edit
git reset --hard origin/main     # ibalik ang branch sa estado ng server

Bago ang --hard, makabubuting patakbuhin ang git status at git stash kung may mahalaga. Maibabalik ang naka-commit (tingnan sa ibaba), pero ang hindi pa naka-commit ay hindi na.

git reset para sa isang file

Kapag may path, hindi ginagalaw ng reset ang branch, binabago lang nito ang index: ang git reset app.py ay inaalis ang file sa mga nahanda na. Ang modernong katumbas nito ay git restore --staged app.py, mas malinaw ito. Hindi gumagana ang --soft at --hard kapag may path.

Paano gumagana ang git revert

Kinukuwenta ng git revert <commit> ang pagbabago ng tinukoy na commit, ina-apply ito sa kabaligtaran na direksyon, at gumagawa ng bagong commit. Binubura ang mga naidagdag na linya, at ibinabalik ang mga nabura. Lumalago ang history pasulong, walang nire-rewrite, kaya walang kailangang ayusin sa panig ng katrabaho.

git log --oneline
# a3f9c21 (HEAD -> main) docs: README
# 7be41d0 feat: cache ng sagot
# 1c02e8f fix: timeout ng request

git revert 7be41d0
# [main 5d8e2aa] Revert "feat: cache ng sagot"
#  2 files changed, 3 insertions(+), 41 deletions(-)

Magbubukas ang Git ng editor na may mensaheng gaya ng Revert "..." at linyang This reverts commit 7be41d0.... Mainam na dagdagan ito ng paliwanag kung bakit inatras ang pagbabago.

Mga kapaki-pakinabang na flag ng revert

  • --no-edit: tanggapin ang default na mensahe nang walang editor.
  • -n (--no-commit): ilagay ang kabaligtarang pagbabago sa index nang hindi gumagawa ng commit. Sa ganitong paraan, puwedeng i-undo ang ilang commit sa iisang commit.
  • git revert A..B: i-undo ang saklaw ng mga commit (bawat isa ay may hiwalay na revert commit, mula bago hanggang luma).
  • -m 1: kailangan para sa merge commit; tinutukoy nito kung aling parent ang ituturing na pangunahing linya.
git revert --no-commit HEAD~3..HEAD
git commit -m "Revert: pag-undo sa tatlong commit ng eksperimento"

Pag-revert ng merge commit

May dalawang parent ang merge, at hindi malalaman ng Git kung alin ang paghahambingan para sa "kabaligtarang" pagbabago, kaya kung walang -m, magbibigay ito ng error na is a merge but no -m option was given. Karaniwang ang pangunahing branch ang unang parent:

git revert -m 1 9f1e2ab

Bitag: kung kalaunan ay gusto ninyong isama ulit ang branch na iyon, ituturing ng Git na nasama na ang mga commit nito, at hindi nito dadalhin ang mga pagbabago. Ang solusyon ay i-revert muna ang revert commit, at pagkatapos ay idagdag ang mga bagong pagbabago.

git reset vs git revert: alin ang piliin

Pamantayangit resetgit revert
Ginagawa sa historyisinusulat muli (nawawala sa branch ang mga commit)nagdaragdag ng bagong commit
Na-push na ang commitkailangan ang push --force, nasisira ang gawa ng katrabahokaraniwang git push
Pag-undo ng commit sa gitna ng historykasama lahat ng sumunod na commitpuwedeng tiyak lang
Bakas sa historywalang natitiranananatili, kita kung sino at bakit nag-rollback
Karaniwang sitwasyonlinisin ang lokal na commit bago mag-pushi-undo ang commit na sumira sa production sa main

Simpleng tuntunin: kung nakita na ng iba ang commit, revert; kung hindi, reset. Ang eksepsiyon ay ang personal ninyong feature branch na walang ibang kumuha: doon, puwedeng isulat muli ang history at mag-push gamit ang git push --force-with-lease.

Bakit masamang ideya ang reset --hard sa shared branch

Isipin: nagpatakbo kayo ng git reset --hard HEAD~2 sa main, tapos git push --force. Nasa mga katrabaho pa rin ang dalawang commit. Sa susunod na git pull, susubukan ng Git na pagsamahin ang kanilang branch sa inyo, at babalik ang "nabura" na commit, kasama ang magulong merge commit. Mas malala pa kung may nag-push na ng kanilang commit sa ibabaw: mabubura lang ng force push ang mga iyon.

Kaya sa mga protektadong branch (main, release), karaniwang ipinagbabawal ng settings ng hosting ang force push. Kung hindi maiiwasan ang pagsulat muli, gamitin ang git push --force-with-lease: tatanggi ito kung may nakita kayong commit sa server na hindi ninyo alam.

Karaniwang sitwasyon ng pag-undo

Paano i-undo ang huling commit na hindi pa na-push

git reset --soft HEAD~1   # nasa index ang mga pagbabago, puwedeng mag-commit ulit
git reset HEAD~1          # nasa mga file ang pagbabago, walang laman ang index
git reset --hard HEAD~1   # itinapon ang mga pagbabago

Kung ang kailangan lang ay ayusin ang mensahe o idagdag ang nakalimutang file, hindi kailangan ng reset: git add nakalimutang.txt at git commit --amend.

Paano i-undo ang commit pagkatapos ng push

git revert <hash>
git push

Ito ang sagot sa madalas itanong na "git reverse commit": walang command na git reverse sa Git. Ang "kabaligtarang" commit ay nililikha ng git revert.

Paano ibalik ang branch sa estado ng server

git fetch origin
git reset --hard origin/main

Kapaki-pakinabang kapag magulo ang lokal na branch pagkatapos ng hindi maayos na rebase o eksperimento. Mawawala sa branch ang lahat ng lokal na commit na wala sa server.

Paano ibalik ang mga commit pagkatapos ng maling reset

Itinatala ng Git ang bawat galaw ng HEAD sa reflog. Nananatili sa object database ang mga commit pagkatapos ng reset nang hindi bababa sa ilang linggo (ayon sa default, 30 araw para sa mga hindi maabot na entry ng reflog).

git reflog
# 1c02e8f HEAD@{0}: reset: moving to HEAD~2
# a3f9c21 HEAD@{1}: commit: docs: README
# 7be41d0 HEAD@{2}: commit: feat: cache ng sagot

git reset --hard a3f9c21   # o HEAD@{1}

Lokal lang ang reflog: nasa clone ninyo lang ito at hindi ipinapadala sa server.

git clean: pagbura ng mga hindi tinatrack na file

Hindi ginagalaw ng git reset --hard ang mga file na hindi tinatrack ng Git: bagong file na hindi pa naidadagdag sa index, mga build artifact, mga log. Para sa mga ito, mayroong git clean. Hindi na maibabalik ang command: ang mga file na nabura nito ay hindi napupunta sa reflog o sa recycle bin.

git clean -n      # dry run: ipakita kung ano ang bubura
git clean -f      # burahin ang mga hindi tinatrack na file
git clean -fd     # kasama rin ang mga hindi tinatrack na folder
git clean -fdx    # kasama rin ang mga naka-ignore na file (.gitignore): node_modules, dist
git clean -i      # interactive na pagpili

Kung wala ang -f, tatanggi ang Git na gumana bilang default (setting na clean.requireForce). Laging magsimula sa -n, lalo na sa -x: buburahin nito pati ang lokal na .env kung nasa ignore list ito.

Pagkombinahin para sa buong reset sa huling commit: git reset --hard && git clean -fd.

Karaniwang pagkakamali

  • Ginamit ang reset --hard sa halip na --soft. Nasasagip ng reflog ang naka-commit, pero nawawala nang tuluyan ang hindi pa naka-commit. Ugaliing mag-git stash bago ang eksperimento.
  • Revert nang walang pag-unawa sa mga dependency. Kung may mas bagong commit na binago ang parehong linya, magkakaroon ng conflict. Ayusin ito tulad ng dati: i-edit ang file, git add, git revert --continue; kung nagbago ang isip, git revert --abort.
  • Pagkalito sa restore at reset. Para i-rollback ang mga edit sa isang file, hindi kailangan ng reset ng buong branch: git restore file ang sapat.
  • Force push sa main. Mas mainam ang revert at karaniwang push, kahit medyo humaba ang history.

Buod

Ang git reset ay kasangkapan para sa sariling history na hindi pa nailalathala: --soft ang nagpapanatili ng mga pagbabago sa index, --mixed sa mga file, at --hard ang nagtatapon ng lahat. Ang git revert ay ligtas na pag-undo sa shared branch, at nag-iiwan ng tapat na bakas sa history. Ang git clean ay naglilinis ng mga hindi tinatrack na file, pero walang puwang sa pagkakamali. Ang mga sitwasyon ng pag-undo gamit ang restore, reset, at revert ay itinuturo nang praktikal sa kursong Git namin.

Mga madalas itanong

Binubura ba ng git reset ang mga commit nang tuluyan?

Hindi, nananatili ang mga commit sa object database at makikita sa git reflog hanggang sa burahin ng garbage collector, na karaniwang nangyayari pagkalipas ng 30 araw para sa mga hindi maabot na entry.

Puwede bang i-undo ang git revert?

Oo. Ang revert commit ay ordinaryong commit, kaya maaari itong i-undo sa pamamagitan ng isa pang git revert, o kung hindi pa naipapadala, tanggalin gamit ang git reset.

Ano ang pagkakaiba ng git reset at git checkout?

Inililipat ng git reset ang pointer ng kasalukuyang branch, habang ang git checkout (o git switch) ay inililipat ang HEAD sa ibang branch o commit nang hindi binabago ang branch mismo.

Ano ang ibig sabihin ng HEAD~1 at HEAD^?

Parehong tumutukoy sa parent ng kasalukuyang commit; ang HEAD~3 ay ang ikatlong ninuno sa pamamagitan ng unang parent, at ang HEAD^2 ay ang pangalawang parent ng merge commit.

Paano i-undo ang git clean?

Gamit ang Git, hindi ito posible: hindi naka-imbak sa repository ang mga hindi tinatrack na file na nabura. Kaya palaging patakbuhin muna ang git clean -n.

Pag-aralan ito sa video

Detalyadong tinatalakay ang paksang ito, may praktis, sa kursong “Git с нуля до уверенного разработчика”.

Pumunta sa kurso