Paghahambing

Git merge vs rebase: alin ang piliin para sa team ninyo

Na-update: · Skillaria.Top

Pareho ang layunin ng merge at rebase na pagsamahin ang mga pagbabago ng branch, pero magkaiba ang paghawak nila sa history: pinananatili ng merge ang history gaya ng dati at nagdadagdag ng merge commit, habang muling isinusulat ng rebase ang inyong mga commit sa ibabaw ng bagong base at ginagawang tuwid ang history. Praktikal na tuntunin: rebase para ayusin ang sarili ninyong hindi pa naipapadalang commit, at merge para isama ang tapos nang trabaho sa shared branch.

Maikli: ano ang pagkakaiba ng merge at rebase

Ang debate ng "merge vs rebase" ay hindi tungkol sa kung aling command ang mas magaling, kundi kung anong history ng project ang gusto ninyong makita. Pareho silang nagbubunga ng iisang code sa huli. Ang landas na naitatala sa log ang nagkakaiba.

  • Merge ay nag-uugnay ng dalawang linya ng history at tapat na nire-record na parallel ang trabaho. Hindi nagbabago ang mga umiiral na commit; nagdaragdag ito ng merge commit na may dalawang parent.
  • Rebase ay muling isinusulat ang inyong mga commit na parang nagsimula kayo ng trabaho sa pinakabagong bersyon ng base branch. Tuwid ang linya ng history, pero may bagong hash ang mga commit.

Ang mekanika ng bawat command (mga flag, pag-ayos ng conflict, interactive mode) ay nasa hiwalay na mga artikulo. Dito, ang pagpili ng estratehiya lang ang tinatalakay.

Itsura ng history sa dalawang kaso

Panimulang sitwasyon: humiwalay kayo sa feature, gumawa ng dalawang commit, habang may dalawang bagong commit ng iba sa main.

          D---E        feature
         /
A---B---C---F---G      main

Pagkatapos ng git merge feature sa main:

          D---E
         /     \
A---B---C---F---G---M  main

Pagkatapos ng git rebase main sa feature at pag-usog ng main:

A---B---C---F---G---D'---E'   main

Sa unang kaso, nakikita sa history na ginawa nang parallel ang feature at kung kailan ito isinama. Sa ikalawa, binabasa ang history bilang sunod-sunod na kuwento, pero wala na ang bakas ng parallel na trabaho: ang D' at E' ay mga bagong commit na nilikha sa sandali ng rebase.

Talaan ng paghahambing ng merge vs rebase

Pamantayangit mergegit rebase
Mga umiiral na commitHindi nagbabagoNilikhang muli na may bagong hash
Hugis ng historyBranching graph na may merge commitLinear
Kaligtasan para sa shared branchLaging ligtasDelikado para sa nai-publish na commit
Kailangan ba ng force pushHindiOo, kung nasa server na ang branch
ConflictInaayos nang isang beses, sa merge commitPuwedeng lumitaw sa bawat inilipat na commit
Konteksto kung saan galingNapapanatiliNawawala
Pag-revert ng buong featureIsang git revert -m 1 sa merge commitRevert sa bawat commit o saklaw
Kaginhawahan sa git bisect at git logMas mahirap basahin ang graphMas simple: isang tuwid na linya
Hadlang sa pagpasokMababaMas mataas, kailangang maintindihan ang pagsusulat muli ng history
Paglilinis ng commit (squash, reword)Squash lang ng buong branch (--squash)Flexible sa pamamagitan ng rebase -i

Mga bentahe at disbentahe ng merge

Mga bentahe

  • Hindi sinisira ang history. Nananatili ang anumang nai-publish. Hindi na kailangang ayusin ng mga katrabaho ang anuman dahil sa ginawa ninyo.
  • Isang beses lang inaayos ang conflict. Kahit 30 commit ang branch, ang kinakaharap ninyo ay ang panghuling estado, hindi bawat hakbang.
  • Napapanatili ang konteksto. Sa merge commit, makikita kung aling task ang pumasok sa pangunahing branch at kailan, at madali itong i-revert nang buo.

Mga disbentahe

  • Maingay na graph. Kapag madalas ang synchronization, dumarami ang mga commit na "Merge branch 'main' into feature", at nagiging parang railway diagram ang git log --graph.
  • Nakapapasok sa history ang mga draft na commit. Ang "wip", "fix", "isa pang fix" ay mananatili sa pangunahing branch magpakailanman, kung hindi ito na-squash.

Mga bentahe at disbentahe ng rebase

Mga bentahe

  • Linear at madaling basahing history. Nasa tamang puwesto ang bawat commit, nababasa ang git log bilang listahan ng mga pagbabago, at mas madaling mahanap ng git bisect ang commit na may error.
  • Puwedeng ayusin ang mga commit bago ang review: pagsamahin, palitan ang pangalan, o ayusin ang pagkakasunod-sunod.
  • Walang teknikal na merge commit mula sa pag-sync sa pangunahing branch.

Mga disbentahe

  • Muling isinusulat ang history. Ang rebase ng nai-publish na shared branch ay sumisira sa gawa ng lahat ng nag-download nito.
  • Kailangan ng force push para sa mga branch sa server, kaya kailangan ng disiplina at --force-with-lease.
  • Paulit-ulit na conflict. Maaaring mag-conflict ang iisang bahagi sa maraming commit na magkakasunod.
  • Maaaring hindi mag-build ang mga intermediate na commit. Pagkatapos ilipat sa bagong base, walang nagte-test ng mga lumang commit sa bagong kapaligiran.

Kailan gagamitin ang alin

Rebase para sa sarili ninyong lokal na trabaho

Ina-update ninyo ang branch bago ipadala: git pull --rebase. Inihahanda ang branch para sa review at gusto ninyong alisin ang mga draft na commit: git rebase -i. Nahuli sa main ang personal ninyong feature branch: git rebase origin/main. Sa lahat ng ito, binabago ang mga commit na ang nakakita lang ay kayo (o pag-aari ninyo lang).

Merge para sa shared branch at integration

Ang tapos nang feature ay isinasama sa main o develop. Maraming tao ang nagtatrabaho sa branch. Kailangang isama ang release branch pabalik sa pangunahing branch. Dito, mahalagang huwag galawin ang mga nai-publish na commit, at ang merge lang ang tamang opsyon.

Simpleng tuntunin sa pagpili

Kung kayo lang ang may hawak ng commit, puwede ang rebase. Kung may nakadownload na nito, merge lang.

Handang daloy ng trabaho para sa team

DaloyPaano gumaganaPara kanino
Merge langAng mga feature ay isinasama gamit ang --no-ff, at ang sync ay git merge mainMga baguhan sa Git, team na mahalaga ang buong chronology at simpleng pag-rollback
Rebase + mergeNire-rebase ang branch sa main bago isama, tapos merge commit na may --no-ffTeam na kailangan ang malinis na history at hangganan ng feature
Rebase + fast-forwardNire-rebase ang branch at isinasama sa pamamagitan ng fast-forward; ganap na linear ang historyMaliliit na team na may maayos na atomic commit
Squash mergeBawat pull request ay nagiging iisang commit sa mainMga team na may maiikling task, kung saan hindi kailangan ang detalyadong history ng branch

Sa GitHub at GitLab, tumutugma ang mga daloy na ito sa mga button na "Create a merge commit", "Rebase and merge", at "Squash and merge". Mainam na payagan sa settings ng repository ang iisang napiling opsyon, para hindi maging halo-halo ang istilo ng history.

Mga setting na nagpapatibay ng pagpili

# pull nang walang dagdag na merge commit
git config --global pull.rebase true

# o: pull na fast-forward lang, kung hindi, error, kayo ang magdedesisyon
git config --global pull.ff only

# laging merge commit kapag nagsasama ng feature
git config --global merge.ff false

Mag-ingat sa merge.ff false: nakakaapekto rin ito sa git pull sa merge mode. Maraming gumagamit ang hindi ito ginagawang global, at sa halip ay tahasang nagta-type ng --no-ff kapag nagsasama ng feature.

Halimbawa: isang task sa dalawang istilo

Ilarawan natin ang totoong sitwasyon. Tatlong araw na ninyong ginagawa ang feature ng payment sa feature/payment, at sa panahong iyon, limang gawain ng iba ang naisama na sa main. Bago ang pull request, kailangang kunin ang bagong main at tiyaking gumagana ang lahat.

Bersyon ng merge

git switch feature/payment
git fetch origin
git merge origin/main
# inayos ang conflict nang isang beses, git add, git commit
git push

Nakakuha ang branch ng commit na "Merge remote-tracking branch 'origin/main' into feature/payment". Normal ang push, at hindi mapapansin ng mga katrabahong nakatingin sa branch ang anuman. Kung ganito kayo mag-sync araw-araw, tatlong ganitong commit ang nasa branch, at mapupunta ang mga ito sa main kasama ng feature kung walang squash.

Bersyon ng rebase

git switch feature/payment
git fetch origin
git rebase origin/main
# inaayos ang conflict habang nagpapatuloy, sa bawat commit: git add, git rebase --continue
git rebase -i origin/main      # opsyonal: pagsamahin ang mga draft na commit
git push --force-with-lease

Mukhang nagsimula ang branch kaninang umaga mula sa sariwang main, walang dagdag na commit, at mas madaling basahin ng reviewer ang mga pagbabago nang hakbang-hakbang. Ang kapalit: force push, at kailangang tiyakin na walang ibang nagko-commit sa branch na ito.

Ano ang makikita ng main sa dulo

Sa pagsasama sa pamamagitan ng pull request, mananatili ang pagkakaiba. Ang estilo ng merge ay magbibigay ng graph na may mga sanga at sync merge; ang estilo ng rebase ay magbibigay ng maayos na kadena ng mga commit ng feature, na puwedeng isama sa pamamagitan ng fast-forward o isang merge commit. Pareho ang code sa dulo, basta magkapareho ang pag-ayos ng conflict.

Paano magdesisyon bilang team

Sagutin ang ilang tanong. May ilang taong nagtatrabaho sa iisang branch? Kung oo, hindi puwede ang rebase sa branch na iyon. Gaano kaexperyensado ang team sa Git? Kung madalas ang mga baguhan, magsimula sa merge at squash merge; pinapatawad nila ang mga pagkakamali. Kailangan ba ng buong chronology para sa audit at pagsusuri ng insidente? Kung oo, kapaki-pakinabang ang mga merge commit ng feature. Mahalaga ba ang mababasang git log at madalas na git bisect? Kung oo, pumanig sa rebase at linear na history.

Itala ang desisyon sa CONTRIBUTING o README ng repository, at i-enable ang proteksyon ng pangunahing branch: bawal ang force push, kailangan ng pull request, at nakatakda ang pinapayagang paraan ng merge. Mas maaasahan ang tuntuning nakatali sa settings kaysa sa kasunduang pasalita lang.

Mga karaniwang maling akala

  • "Advanced ang rebase, para sa baguhan ang merge." Hindi: magkaiba ang kasangkapan para sa magkaibang gawain. Gumagamit ng pareho ang mga beteranong developer.
  • "Basura ang merge commit." Ang mga sync merge, oo, kadalasang ingay. Pero ang merge commit ng pagsasama ng feature ay mahalagang punto: dito makikita at maibabalik ang buong task.
  • "Kapag rebase, mas kaunti ang conflict." Pareho ang conflict, dahil pareho ang mga linyang nagbabago. Hinahati lang ng rebase ang mga ito ayon sa commit, samantalang inaayos ng merge ang lahat nang sabay.
  • "Nawawala ang mga commit sa rebase." Nananatili ang mga lumang commit sa git reflog at mababawi ang mga ito, hangga't hindi sila nabubura ng garbage collection.

Buod

Ang pagpili sa pagitan ng merge at rebase ay pagpili sa pagitan ng tapat na chronology at mabasang linear na history. Ligtas ang merge at pinananatili ang konteksto; nagbibigay ang rebase ng kalinisan, pero muling isinusulat ang mga commit. Ang pinakamaaasahang gawi ay pagsamahin ang dalawa: i-rebase at linisin ang sarili ninyong branch habang kayo pa lang ang may hawak nito, at isama ang tapos nang trabaho sa shared branch gamit ang merge o squash ayon sa tuntunin ng team. Ang pinakamahalaga ay magkasundo sa isang daloy at itatak ito sa settings ng repository. Ang dalawang estratehiya at ang pagtutulungan sa branch ay itinuturo nang praktikal sa kursong Git namin.

Mga madalas itanong

Alin ang gagamitin sa git pull, merge o rebase?

Para sa pag-update ng lokal na branch, mas maginhawa ang rebase: mailalagay ang inyong hindi pa naipapadalang commit sa ibabaw ng bagong remote nang walang dagdag na merge commit. Ina-enable gamit ang git config --global pull.rebase true.

Puwede bang paghaluin ang merge at rebase sa iisang project?

Oo, at ito ang pinakakaraniwang paraan: rebase para sa sarili ninyong branch, merge para sa shared. Ang mahalaga ay alam ng buong team ang tuntunin.

Ano ang dapat piliin ng baguhan?

Magsimula sa merge: hindi nito binabago ang history, kaya mahirap masira ang anuman. Pag-aralan ang rebase sa sarili ninyong lokal na branch kapag nakilala na ninyo ang reflog at force push.

Naaapektuhan ba ng pagpili ng estratehiya ang code sa dulo?

Hindi, kapag magkapareho ang pag-ayos ng conflict, magkapareho ang panghuling estado ng mga file. Ang pagkakaiba lang ay ang naitalang history ng commit.

Ano ang pagkakaiba ng squash merge at rebase?

Pinagsasama ng squash merge ang buong branch sa iisang bagong commit sa pangunahing branch, habang inililipat ng rebase ang bawat commit nang hiwalay. Pareho silang nagbibigay ng linear na history, pero nawawala ang detalye ng bawat hakbang sa squash.

Pag-aralan ito sa video

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

Pumunta sa kurso