git rebase: jinsi inavyofanya kazi, hali ya mwingiliano na kuunganisha commits
git rebase inahamisha commits za tawi la sasa kwenye msingi mpya: Git inaondoa commits zako kwa muda, inasogeza tawi hadi mwisho wa lile lililoteuliwa na kuzitumia tena kama commits mpya. Hivyo unapata historia ya mstari bila commits za merge, na kwa git rebase -i commits zinaweza kuunganishwa (squash), kubadilishwa jina au kufutwa; kuandika upya historia ni salama tu kwa commits ambazo bado hazijachapishwa kwa wengine.
Git rebase inafanya nini
git rebase «inahamisha» tawi lako hadi sehemu nyingine ya historia. Tuseme uliitoa feature kutoka main wiki iliyopita, na tangu hapo main imesonga mbele. Baada ya rebase tawi lako linaonekana kana kwamba umeanza kazi sasa hivi — kutoka commit mpya kabisa ya main.
git switch feature
git fetch origin
git rebase origin/main
Ndani kuna hatua tatu. Git inapata babu wa pamoja wa matawi mawili, inahifadhi mabadiliko ya kila commit yako baada yake kwa zamu, inasogeza tawi hadi origin/main, na kisha inatumia tena mabadiliko yale yaliyohifadhiwa, moja baada ya jingine. Matokeo ni commits mpya zenye maudhui na ujumbe ule ule, lakini hash tofauti.
Kabla: A---B---C---F---G main
\
D---E feature
Baada: A---B---C---F---G main
\
D'---E' feature
Alama ya kistari kwenye D' na E' si pambo. Hizi ni vitu vingine vyenye hash tofauti, na vina mzazi tofauti. Kutoka hapo kunatokea kanuni kuu ya rebase, ambayo iko hapa chini.
Kanuni ya dhahabu: usiweke upya kilichochapishwa
Rebase inaandika upya historia. Ikiwa commits ni zako pekee, hilo ni salama. Lakini ukiwa tawi limepakuliwa na wenzako, baada ya rebase watakuwa na D na E za zamani, wewe una D' na E' mpya, na pull ijayo itafanya historia kurudiwa mara mbili, na conflicts zitatatuliwa tena.
Kanuni ya vitendo: rebase inatumika kwenye matawi yako ya ndani na kwenye matawi binafsi ya feature ambayo mtu mmoja anafanyia kazi. Matawi ya pamoja — main, develop, na matawi ya release — hayawekwi upya kamwe.
Jinsi ya kutuma tawi baada ya rebase
Ikiwa tawi tayari lilikuwa kwenye seva, push ya kawaida itakataliwa: historia ya ndani haiendelei tena ile ya mbali. Unahitaji force push, na toleo lake salama:
git push --force-with-lease
Tofauti na --force, bendera --force-with-lease inakataa kuandika juu ya tawi ikiwa kwenye seva kuna commits ambazo hukuziona. Kwa njia hii hutafuta kazi ya mtu mwingine kwa bahati mbaya.
Conflicts wakati wa rebase
Kwa kuwa commits zinatumika moja moja, conflict inaweza kutokea kwenye commit yoyote — na hata mara kadhaa mfululizo. Git inasimama na kukujulisha ni commit ipi imeshindwa kutumika.
$ git rebase origin/main
Auto-merging src/api.js
CONFLICT (content): Merge conflict in src/api.js
error: could not apply 4e1f9a2... Ongeza akiba ya maombi
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
Hatua za kufuata:
- Fungua faili lenye conflict, chagua toleo sahihi, na ondoa alama
<<<<<<<,=======,>>>>>>>. - Weka alama kwamba faili limetatuliwa:
git add src/api.js. Hakuna haja ya commit. - Endelea:
git rebase --continue. Git itatumia commit inayofuata.
Amri nyingine za kudhibiti mchakato:
| Amri | Inafanya nini |
|---|---|
git rebase --continue | Kuendelea baada ya kutatua conflict |
git rebase --skip | Kuruka commit ya sasa kabisa (mabadiliko yake yanapotea) |
git rebase --abort | Kusimamisha rebase na kurudisha tawi kwenye hali yake ya awali |
Angalia mchanganyiko wa upande «wetu» na «wao». Wakati wa rebase, HEAD ni msingi ambao unahamishia tawi, na mabadiliko «yanayoingia» ni commits zako mwenyewe. Kwa hiyo git checkout --ours wakati wa rebase inachukua toleo kutoka main, na --theirs — lako. Kwenye merge ni kinyume.
Conflicts zinazojirudia: rerere
Ukiweka upya tawi refu mara kwa mara na kutatua conflict ile ile tena na tena, washa git config --global rerere.enabled true. Git itakumbuka jinsi ulivyoitatua, na mara nyingine itatumia suluhisho lile yenyewe.
Rebase shirikishi: kupanga historia kabla ya kuchapisha
Kitu chenye thamani zaidi katika rebase ni hali ya mwingiliano. Inakuwezesha kupanga commits zako kabla ya kuziweka mbele ya wakaguzi: kuunganisha «fix», «fix typo», «fix zaidi» kuwa commit moja yenye maana, kuandika upya ujumbe, kubadilisha mpangilio, au kutupa kisichohitajika.
git rebase -i HEAD~4 # commits 4 za mwisho
git rebase -i origin/main # commits zote za tawi ambazo hazipo kwenye main
Git itafungua kihariri chenye orodha ya commits — kutoka za zamani hadi mpya (tofauti na git log):
pick 1a2b3c4 Ongeza fomu ya kuingia
pick 5d6e7f8 fix
pick 9a0b1c2 Uthibitishaji wa barua pepe
pick 3d4e5f6 kosa la kuandika katika uthibitishaji
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash" but keep only the previous commit's log message
# d, drop = remove commit
Badilisha neno mwanzoni mwa mstari, hifadhi na funga kihariri — Git itatekeleza mpango kutoka juu kwenda chini.
| Amri | Athari |
|---|---|
pick | Kuacha commit kama ilivyo |
reword | Kuacha mabadiliko, lakini kuandika upya ujumbe |
edit | Kusimama kwenye commit ili kubadilisha yaliyomo (git commit --amend) au kuigawa kwa commits kadhaa |
squash | Kuiingiza kwenye commit iliyotangulia, ujumbe wao unaunganishwa na kuhaririwa |
fixup | Kuiingiza kwenye commit iliyotangulia, ujumbe wa commit hii unatupwa |
drop | Kufuta commit pamoja na mabadiliko yake |
Kubadilisha mpangilio wa mistari kunabadilisha mpangilio wa commits, na kufuta mstari kunalingana na drop.
Git squash: kuunganisha commits kuwa moja
Hakuna amri tofauti ya git squash kwenye Git. Kuunganisha commits (squash) kunawezekana kwa njia tatu, na rebase shirikishi ndiyo yenye unyumbufu zaidi.
Njia ya 1. Rebase shirikishi
Kwa mfano hapo juu, tugeuze commits nne kuwa mbili nadhifu:
pick 1a2b3c4 Ongeza fomu ya kuingia
fixup 5d6e7f8 fix
pick 9a0b1c2 Uthibitishaji wa barua pepe
fixup 3d4e5f6 kosa la kuandika katika uthibitishaji
Commit ya kwanza katika kundi lazima ibaki pick: squash na fixup zinaingiza commit kwenye iliyotangulia, na ya kwanza kabisa haina iliyotangulia ya kuingizwa.
Njia ya 2. fixup-commits na autosquash
Ikiwa tayari unajua commit gani unarekebisha, unda marekebisho yakiwa yamewekwa alama tangu mwanzo:
git commit --fixup=1a2b3c4
git rebase -i --autosquash origin/main
Git itaweka fixup-commit chini ya ile sahihi na kuiweka alama kama fixup — unabaki tu kuhifadhi mpango. Tabia hii unaweza kuiwasha kwa chaguo-msingi kwa git config --global rebase.autoSquash true.
Njia ya 3. Kubana tawi zima kuwa commit moja
git reset --soft $(git merge-base HEAD origin/main)
git commit -m "Kuingia kwa barua pepe na uthibitishaji"
reset --soft inarudisha kielekezi cha tawi hadi mahali pa kutengana, lakini inabakiza mabadiliko yote kwenye index — unabaki kufanya commit moja. Chaguo jingine ni git merge --squash wakati wa kuunganisha kwenye tawi kuu, au kitufe «Squash and merge» kwenye pull request.
Chaguo muhimu za rebase
git pull --rebase
Pull ya kawaida inaunganisha tawi la mbali kwenye lako na kuunda commit ya merge ikiwa ulikuwa unafanya commits sambamba na wenzako. git pull --rebase badala yake inapanga upya commits zako za ndani juu ya zile mpya kutoka mbali. Kuiweka kama tabia ya chaguo-msingi: git config --global pull.rebase true. Huu ndio ukanda salama wa rebase — commits zako za ndani bado hazijaonwa na mtu yeyote.
--onto: kuhamisha sehemu ya tawi
Uliitoa feature-b kutoka feature-a, na sasa unataka feature-b itoke moja kwa moja kwenye main, bila commits za feature-a:
git rebase --onto main feature-a feature-b
Inasomeka hivi: chukua commits za feature-b ambazo hazipo kwenye feature-a, na uzipandikize kwenye main.
--exec: kukagua kila commit
git rebase -i --exec "npm test" origin/main
Baada ya kila commit kutumika, majaribio yanaendeshwa; yakianguka, rebase inasimama kwenye commit yenye tatizo. Ni muhimu pale ambapo kila commit ya historia inapaswa kujengwa.
--update-refs: rundo la matawi yanayotegemeana
Ukiwa na mnyororo wa matawi yanayotegemeana, bendera --update-refs (Git 2.38+) inapohamisha tawi la juu inasogeza pia la kati.
Jinsi ya kughairi rebase
Ikiwa mchakato bado unaendelea — git rebase --abort. Rebase ikishakamilika na matokeo hayakufurahisha, commits za zamani hazijapotea: zinakumbukwa na jarida la marejeo.
$ git reflog
e5f6a7b HEAD@{0}: rebase (finish): returning to refs/heads/feature
e5f6a7b HEAD@{1}: rebase (pick): Uthibitishaji wa barua pepe
...
c3d4e5f HEAD@{5}: commit: kosa la kuandika katika uthibitishaji
$ git reset --hard HEAD@{5}
Tafuta kwenye git reflog kiingilio kilichotangulia mwanzo wa rebase, kisha weka upya tawi kwake. Mara baada ya rebase pia kuna njia fupi: git reset --hard ORIG_HEAD. Reflog inahifadhiwa kwenye kompyuta yako na kwa chaguo-msingi inashikilia takriban siku 90, kwa hiyo hakuna haja ya kuogopa baada ya rebase iliyoshindwa.
Makosa ya kawaida
- Umeweka upya tawi la pamoja na kufanya force push — historia ya wenzako imevurugika. Suluhisho: kukubaliana, kurejesha tawi kutoka reflog ya mtu aliye na toleo sahihi, na kuzuia force push kwenye matawi yaliyolindwa kwenye seva.
- Kutumia
--forcebadala ya--force-with-lease— na kufuta commit ambayo mwenzako alikuwa ameitumia kwenye tawi hilo hilo. - Squash kwenye mstari wa kwanza wa mpango wa mwingiliano — Git itajibu kwa hitilafu «cannot 'squash' without a previous commit».
- Kuanza rebase ukiwa na saraka chafu. Git itakataa kuanza. Weka commit kwa mabadiliko yako, yaweke kwenye
git stash, au tumiagit rebase --autostash. - Kutatua conflict kisha kufanya
git commitbadala yagit rebase --continue. Itatokea commit ya ziada; baada ya--continueunaweza kuiondoa kwa rebase shirikishi nyingine.
Muhtasari
git rebase inahamisha commits zako kwenye msingi mpya na kuziunda upya, hivyo historia inabaki mstari mmoja na safi. Hali ya mwingiliano inageuza rasimu kuwa historia nadhifu: squash na fixup zinaunganisha marekebisho, reword inarekebisha ujumbe, drop inaondoa kisichohitajika. Kanuni kuu ni moja — weka upya tu kile ambacho bado hujakichapisha kwa wengine, na baada ya kuweka upya tawi lako la mbali litume kwa --force-with-lease. Kazi na rebase na usafishaji wa historia ya commits vinafanyiwa mazoezi ya vitendo katika kozi ya Git.
Maswali ya mara kwa mara
Je, git rebase inabadilisha maudhui ya msimbo?
Ikiwa hakuna conflicts, maudhui ya mwisho ya faili yatakuwa sawa na ya merge, lakini commits zenyewe zinaundwa upya na hash mpya na wazazi wapya. Ikiwa wakati wa conflict ulichagua chaguo tofauti, commits za kati zitatofautiana na za asili.
Nawezaje kuweka upya tawi juu ya commit ya kwanza kabisa ya hifadhi?
Tumia git rebase -i --root: mpango utajumuisha commits zote, pamoja na ile ya mizizi. Hili linahitajika mara chache, kwa mfano kubadilisha ujumbe wa commit ya kwanza kabisa.
Je, rebase inahifadhi mwandishi na tarehe za commits?
Mwandishi na tarehe ya uandishi vinabaki, lakini committer na tarehe ya commit zinabadilika kuwa za sasa. Bendera --committer-date-is-author-date inaweka tarehe ya commit sawa na tarehe ya uandishi.
Je, inawezekana kuweka upya commits za merge?
Kwa chaguo-msingi rebase inanyoosha historia na kuondoa commits za merge. Ili kuhifadhi muundo wa muunganisho, tumia git rebase --rebase-merges.
Nitajuaje kwamba rebase inaendelea sasa hivi?
git status itaonyesha mstari interactive rebase in progress au You are currently rebasing, na kueleza amri zinazopatikana. Shell nyingi na IDE pia zinaonyesha hali hii kwenye kidokezo.
Mada hii inafundishwa kwa kina pamoja na mazoezi katika kozi “Git kutoka mwanzo hadi msanidi programu anayejiweza”.
Nenda kwenye kozi