git merge: jinsi ya kuunganisha matawi na kusuluhisha conflicts
git merge inaunganisha historia ya tawi lingine na la sasa: ikiwa tawi la sasa halijasonga mbele, Git inasogeza kielekezi tu (fast-forward), vinginevyo inaunda commit ya merge yenye wazazi wawili. Hamia tawi lengwa kisha tekeleza git merge jina-la-tawi; ikitokea conflict, rekebisha faili, fanya git add na git commit, au ghairi yote kwa git merge --abort.
Git merge inafanya nini
Amri git merge inachukua mabadiliko kutoka tawi lililotajwa na kuyaingiza kwenye tawi ulilopo sasa. Jambo la kukumbuka ni mwelekeo: unaunganisha «ndani ya yenyewe». Ili kuingiza feature/login kwenye main, kwanza unahamia main, kisha unaita muunganisho.
git switch main
git pull # vuta main mpya kutoka seva
git merge feature/login
Git haikopi mistari moja moja «kwa mkono». Inatafuta babu wa pamoja wa matawi mawili (merge base), inalinganisha matoleo yote mawili nayo na kuweka mabadiliko pamoja. Ikiwa pande zote mbili zilibadilisha sehemu tofauti, matokeo yanapatikana kiotomatiki. Ikiwa zilibadilisha sehemu ile ile — conflict hutokea, na uamuzi ni wako.
Njia mbili: fast-forward na merge ya pande tatu
Fast-forward — wakati commit ya merge haihitajiki
Tuseme uliitoa feature kutoka main, ukafanya commits tatu, na wakati huo hakuna aliyeongeza chochote kwenye main. Basi historia ya main ni mwanzo tu wa historia ya feature. Git inasogeza kielekezi cha main mbele hadi commit ya mwisho ya feature, na hakuna commit mpya inayoundwa.
$ git merge feature
Updating 3f2a1c4..9b7e0d2
Fast-forward
src/auth.js | 42 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
Historia inabaki mstari mmoja, lakini ukweli kwamba «hapa kulikuwa na tawi la feature» unapotea. Wakati mwingine hilo ni zuri, wakati mwingine si — tazama hapa chini sehemu ya --no-ff.
Merge ya pande tatu na commit ya merge
Ikiwa matawi yote mawili yamesonga mbele kutoka babu wa pamoja, kusogeza kielekezi hakuwezekani tena. Git inafanya merge ya pande tatu: msingi, upande «wetu» (tawi la sasa) na upande «wao» (tawi linalounganishwa). Matokeo yanarekodiwa kwenye commit tofauti ya merge, yenye wazazi wawili.
$ git merge feature
Merge made by the 'ort' strategy.
src/auth.js | 42 ++++++++++++++++++++
src/router.js | 3 +-
2 files changed, 44 insertions(+), 1 deletion(-)
Git itafungua kihariri chenye ujumbe kama Merge branch 'feature'. Unaweza kuuacha au kuongeza sababu ya muunganisho. Ili kuona «mpasuko» uliotokea, tumia:
git log --oneline --graph --all
Mkakati ort ndio chaguo-msingi kuanzia Git 2.34; awali ulikuwa recursive. Kwa kazi ya kila siku hakuna haja ya kubadilisha mkakati.
Bendera muhimu za git merge
| Bendera | Inafanya nini | Lini inasaidia |
|---|---|---|
--no-ff | Daima inaunda commit ya merge, hata pale fast-forward inawezekana | Unataka kuona kwenye historia commits zipi zilitoka kwenye kipengele kimoja |
--ff-only | Inaunganisha kwa kusogeza tu, vinginevyo inashindwa kwa hitilafu | Kusasisha tawi la ndani bila commits za merge zisizo za lazima |
--squash | Inaweka mabadiliko yote ya tawi kwenye index, lakini haifanyi commit wala kuunganisha uhusiano na tawi | Unataka kugeuza kipengele kuwa commit moja nadhifu |
--no-commit | Inatekeleza muunganisho lakini inasimama kabla ya commit | Unataka kuhakiki matokeo au kuendesha majaribio kabla ya kuweka commit |
-m "maandishi" | Inaweka ujumbe wa commit ya merge | Muunganisho kwenye scripts bila kihariri |
--abort | Inaghairi merge iliyoanzishwa na kurudisha hali ya kabla yake | Conflicts ni nyingi mno na unataka kuanza upya |
--continue | Inakamilisha merge baada ya kusuluhisha conflicts | Mbadala wa git commit katika hatua ya mwisho |
-X ours / -X theirs | Kwenye vipande vinavyogongana, inachukua toleo letu au lao kiotomatiki | Unajua hakika toleo lipi ni sahihi (kwa tahadhari!) |
--no-ff: kuhifadhi mipaka ya kipengele
Timu nyingi huunganisha vipengele kwa --no-ff pekee. Hapo kwenye grafu kila kazi inaonekana kama «kiputo», na inaweza kughairiwa kwa amri moja git revert -m 1 <commit-ya-merge>. Kwa fast-forward hakuna kituo kama hicho, na kughairi kungelazimu kuondoa kila commit kivyake.
--squash: commit moja badala ya kumi
git switch main
git merge --squash feature/login
git commit -m "Kuingia kwa barua pepe na nywila"
Baada ya --squash, Git haichukulii tawi kuwa limeunganishwa: git branch -d feature/login itakataa kulifuta kwa onyo «not fully merged». Lifute kwa git branch -D ukishahakikisha kila kitu kipo. Na usiendelee kufanya kazi kwenye tawi lile lile baada ya squash — muunganisho ujao utaleta mabadiliko yaliyokwisha kuingia tena, na karibu hakika utatoa conflicts.
Conflict ya muunganisho: jinsi ya kuisuluhisha
Conflict ni hali ya kawaida ya kazi, si ajali. Maana yake ni moja: matawi mawili yamebadilisha mistari ile ile (au mmoja amefuta faili ambalo lingine lilikuwa likilibadilisha), na Git haijaribu kukisia toleo lipi ni sahihi.
$ git merge feature/login
Auto-merging src/config.js
CONFLICT (content): Merge conflict in src/config.js
Automatic merge failed; fix conflicts and then commit the result.
Hatua ya 1. Angalia kinachogongana
$ git status
On branch main
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: src/config.js
Hatua ya 2. Hariri faili
Kwenye faili lenye conflict, Git inaweka alama:
<<<<<<< HEAD
const TIMEOUT = 5000;
=======
const TIMEOUT = 10000;
>>>>>>> feature/login
Sehemu ya juu ni tawi lako la sasa (HEAD), ya chini ni tawi linalounganishwa. Acha toleo sahihi (au unganisha yote mawili), ondoa mistari mitatu ya alama, kisha uhifadhi faili. Kosa la kawaida ni kusahau alama mahali fulani katikati ya faili; kabla ya commit zitafute: git diff --check itaonyesha alama zilizobaki.
Hatua ya 3. Weka alama ya suluhisho na umalize muunganisho
git add src/config.js
git commit # au git merge --continue
Ikiwa conflict inatatuliwa kwa kuchagua upande mmoja tu, si lazima kuhariri faili kwa mkono:
git checkout --ours src/config.js # acha toleo la tawi la sasa
git checkout --theirs src/config.js # chukua toleo la tawi linalounganishwa
git add src/config.js
Ni rahisi zaidi kwenye kihariri
VS Code, IDE za JetBrains na wahariri wengine wanaonyesha conflict kwa safu tatu na wana vitufe vya «kubali la sasa / linaloingia / yote mawili». Unaweza pia kuunganisha zana ya nje kupitia git mergetool. Mpangilio muhimu ni git config --global merge.conflictStyle zdiff3: kwenye alama pia itaonekana toleo la awali kutoka babu wa pamoja, na inakuwa wazi nani alibadilisha nini.
Umebadili nia — ghairi muunganisho
git merge --abort
Amri hii inarudisha saraka ya kazi na index kwenye hali ya kabla ya git merge. Kwa hiyo kabla ya kuunganisha ni vizuri kuwa na saraka ya kazi safi: weka commit au uhifadhi kazi ambayo haijakamilika kwa git stash, vinginevyo itakuwa vigumu kuitenganisha na matokeo ya muunganisho.
Jinsi ya kughairi merge iliyokwisha kufanyika
Ikiwa commit ya merge bado haijatumwa kwenye seva, njia rahisi ni kurudisha tawi nyuma:
git reset --hard ORIG_HEAD
ORIG_HEAD Git huiandika kabla ya operesheni hatari, ikiwemo merge — ni nafasi ya tawi kabla ya merge. Bendera --hard inatupa mabadiliko ambayo hayajawekwa commit, kwa hiyo angalia git status kwanza.
Ikiwa muunganisho tayari uko kwenye hifadhi ya pamoja, historia haiandikwi upya. Badala yake unaunda commit ya kinyume:
git revert -m 1 a1b2c3d
Bendera -m 1 inasema kwamba «mkuu» ni mzazi wa kwanza (tawi ambalo muunganisho ulifanyika ndani yake). Angalia mtego: baada ya revert kama hii Git inachukulia commits za kipengele tayari zimeingia. Ukitaka kuingiza kipengele kilichorekebishwa baadaye, lazima kwanza ughairi revert yenyewe.
Merge katika kazi ya timu
git pull ni fetch pamoja na merge
Kwa kawaida git pull inapakua mabadiliko na kuunganisha tawi la mbali kwenye la ndani. Ukifanya commits sambamba na mwenzako, utaona commit «Merge branch 'main' of ...». Ili kuepuka muunganisho wa kiufundi kama huo, weka git config --global pull.ff only (pull inashindwa ikiwa kusogeza hakuwezekani, na unaamua mwenyewe) au tumia git pull --rebase.
Pull request na kitufe cha Merge
Kwenye GitHub na GitLab muunganisho kwa kawaida unafanyika kupitia pull/merge request. Kitufe «Create a merge commit» kinalingana na git merge --no-ff, «Squash and merge» — muunganisho wa kubana, «Rebase and merge» — kupanga upya. Kuchagua hali ni makubaliano ya timu, lakini utaratibu wenyewe ni ule ule wa terminal.
Kuingiza main kwenye tawi lako
Tawi linaloishi muda mrefu linatofautiana na main, na conflicts zinajilimbikiza. Vuta tawi kuu kwako mara kwa mara:
git switch feature/login
git fetch origin
git merge origin/main
Hivyo conflicts zinasuluhishwa kwa vipande vidogo kadiri zinavyotokea, na muunganisho wa mwisho kwenye main unapita kwa urahisi.
Makosa ya kawaida
- Umeunganisha upande usio sahihi. Umetekeleza
git merge mainukiwa kwenyemain, au umeingiza kipengele kwenye kipengele kingine. Kabla ya kuunganisha hakiki tawi la sasa kwagit branch --show-current. - Muunganisho na tawi lililopitwa na wakati. Uliunganisha
mainya ndani iliyokaa wiki bila kusasishwa. Kwanzagit pull, kisha merge. - «Your local changes would be overwritten by merge». Kuna mabadiliko ambayo hayajawekwa commit kwenye faili zile zile. Yawekee commit au yaweke kwenye stash.
- «refusing to merge unrelated histories». Matawi hayana babu wa pamoja — kwa mfano hifadhi ya ndani iliundwa kwa
git init, na ile ya mbali tayari ina README. Ikiwa muunganisho ni wa lazima kweli, ongeza--allow-unrelated-histories. - Commit iliyo na alama za conflict. Ujenzi unavunjika kwenye
<<<<<<<. Tumiagit diff --checkna endesha majaribio kabla ya commit.
Muhtasari
git merge ni njia salama ya kuunganisha matawi: haiandiki upya commits zilizopo, inaongeza mpya tu (au inasogeza kielekezi). Unganisha kwenye tawi la sasa, weka saraka ya kazi safi, tumia --no-ff ikiwa mipaka ya vipengele ni muhimu, na --squash ikiwa unataka commit moja. Conflicts zinasuluhishwa kwa hatua tatu: kuhariri faili, git add, git commit; na git merge --abort itakurudisha kwenye mahali pa kuanzia wakati wowote. Kuunganisha matawi na kusuluhisha conflicts vinafanyiwa mazoezi ya vitendo katika kozi ya Git.
Maswali ya mara kwa mara
git merge inatofautianaje na git pull?
git pull kwanza inapakua mabadiliko kutoka seva (git fetch), kisha inaunganisha tawi la mbali kwenye la sasa kwa git merge au, ikiwa imesanidiwa hivyo, kwa rebase. git merge inafanya kazi tu na kilichopo kwenye kompyuta yako.
Je, inawezekana kuunganisha matawi kadhaa kwa mara moja?
Ndiyo, git merge feature-a feature-b inafanya muunganisho wa octopus wenye wazazi wengi, lakini tu ikiwa hakuna conflicts. Kwa vitendo matawi kwa kawaida huunganishwa moja moja.
Nawezaje kuona matawi ambayo tayari yameunganishwa kwenye la sasa?
git branch --merged inaonyesha matawi yaliyoingia kikamilifu kwenye la sasa, na git branch --no-merged — yale ambayo bado hayajaunganishwa. Matawi yaliyounganishwa yanaweza kufutwa salama kwa git branch -d.
Nawezaje kuona mapema kile ambacho muunganisho utaleta?
Tekeleza git log main..feature kuona commits zisizo kwenye main, na git diff main...feature kuona mabadiliko ya tawi kuhusiana na babu wa pamoja.
ORIG_HEAD baada ya merge ni nini?
Ni rejeo ambalo Git huihifadhi kabla ya muunganisho: linaelekeza kwenye nafasi ya tawi kabla ya merge. Kwa git reset --hard ORIG_HEAD unaweza kurudisha muunganisho wa ndani, mradi bado haujatumwa kwenye seva.
Mada hii inafundishwa kwa kina pamoja na mazoezi katika kozi “Git kutoka mwanzo hadi msanidi programu anayejiweza”.
- Matawi: Uhalisia Sambamba wa Msimbo Wako
- Migogoro ya Kuunganisha Mabadiliko: Usiogope — Tuchambue na Tutatue