Git
Chapters ▾ 2nd Edition

3.2 Pag-branch ng Git - Batayan ng Pag-branch at Pag-merge

Batayan ng Pag-branch at Pag-merge

Dumaan tayo patungo sa isang simpleng halimbawa ng pag-branch at pag-merge sa isang daloy ng trabaho na maaaring mong gamitin sa tunay na mundo. Susundin mo ang mga hakbang na ito:

  1. Magsagawa ng ilang trabaho sa isang website.

  2. Gumawa ng isang branch para sa isang panibagong kwento na iyong tinatrabaho.

  3. Magsagawa ng ilang trabaho sa branch na iyon.

Sa puntong ito, makakatanggap ka ng isang tawag na ang ibang isyu ay kritikal at kinakailangan mo ng isang hotfix. Gagawin mo ang sumusunod:

  1. Lumipat sa iyong produksyon na branch.

  2. Gumawa ng isang branch upang idagdag ang hotfix.

  3. Pagkatapos itong i-test, i-merge ang hotfix na branch, at i-push sa produksyon.

  4. Lumipat pabalik sa iyong orihinal na kwento at magpatuloy sa pagtrabaho.

Batayan sa Pag-branch

Una, sabihin nating ikaw ay nagtatrabaho sa iyong proyekto at mayroon nang dalawang commit sa master na branch.

Isang simpleng kasaysayan ng commit.
Figure 18. Isang simpleng kasaysayan ng commit

Pinili mong magtrabaho sa isyu #53 sa anumang issue-tracking na sistema na ginagamit ng iyong kumpanya. Upang makagawa ng isang panibagong branch at lumipat dito sa parehong oras, maaari mong patakbuhin ang git checkout na utos na may -b na switch:

$ git checkout -b iss53
Switched to a new branch "iss53"

Ito ay takigrapya para sa:

$ git branch iss53
$ git checkout iss53
Paggawa ng isang panibagong branch na pointer.
Figure 19. Paggawa ng isang panibagong branch na pointer

Ikaw ay nagtatrabaho sa iyong website at gumawa ng ilang mga commit. Ang paggawa nito ay naglilipat sa iss53 na branch nang pasulong, dahil na-check out mo ito (iyon ay, ang iyong HEAD ay nakaturo nito):

$ vim index.html
$ git commit -a -m 'added a new footer [issue 53]'
Ang `iss53` na branch ay nailipat nang pasulong kasama ng iyong trabaho.
Figure 20. Ang iss53 na branch ay nailipat nang pasulong kasama ng iyong trabaho

Ngayon makukuha mo ang tawag na may isang isyu sa website, at kailangan mo itong ayusin kaagad. Gamit ang Git, hindi mo na kailangang i-deploy ang iyong pag-ayos kasama ang iss53 na mga pagbabago na iyong ginawa, at hindi mo na kailangang maglagay ng maraming pagsisikap sa pagpapabalik ng mga pagbabagong iyon bago ka maaaring magtrabaho sa paglalapat ng iyong pag-ayos sa anumang nasa produksyon. Ang kailangan mo lang gawin ay lumipat pabalik sa iyong master na branch.

Subalit, bago mo gawin iyon, tandaan na kung ang iyong tinatrabaho na direktoryo o staging na lawak ay mayroong hindi naka-commit na mga pagbabago na salungatan sa branch na iyong na-check out, Ang Git ay hindi ka hahayaang maglipat ng mga branch. Pinakamainam na magkaroon ng isang malinis na estado ng tinatrabaho kapag ikaw ay maglilipat ng mga branch. May mga paraan upang makaligtaan ito (katulad, ang pag-stash at pag-amend ng commit) na masasakop natin mamaya, sa Pag-stash at Paglilinis. Sa ngayon, ipalagay natin na na-commit mo na lahat ang iyong mga pagbabago, kaya maaari ka nang lumipat pabalik sa iyong master na branch:

$ git checkout master
Switched to branch 'master'

Sa puntong ito, ang iyong tinatrabaho na direktoryo ng iyong proyekto ay eksakto kung paano ito bago mo sinimulang magtrabaho sa isyu #53, at maaari mo nang pag-isiping mabuti ang iyong hotfix. Ito ay isang importanteng punto na dapat tandaan: kapag ikaw ay maglilipat ng mga branch, ang Git ay ire-reset ang iyong tinatrabaho na direktoryo upang magmukha itong kagaya sa huling pagkakataon na ikaw ay nag-commit sa branch na iyon. Ito ay awtomatikong nagdaragdag, nagtatanggal, at nagbabago ng mga files upang siguraduhing ang iyong tinatrabaho na kopya ay kagaya ng kung ano ang mukha ng branch sa iyong huling commit.

Susunod, mayroon kang isang hotfix na gagawin. Gumawa tayo ng isang hotfix na branch kung saan tatrabahuin hanggang sa ito ay matapos:

$ git checkout -b hotfix
Switched to a new branch 'hotfix'
$ vim index.html
$ git commit -a -m 'fixed the broken email address'
[hotfix 1fb7853] fixed the broken email address
 1 file changed, 2 insertions(+)
Ang Hotfix na branch ay nakabatay sa `master`.
Figure 21. Ang Hotfix na branch ay nakabatay sa master

Maaari mong patakbuhin ang iyong mga test, siguraduhing ang hotfix ay kung ano ang iyong gusto, at sa wakas i-merge ang hotfix na branch pabalik sa iyong master na branch upang i-deploy sa produksyon. Gawin mo ito gamit ang git merge na utos:

$ git checkout master
$ git merge hotfix
Updating f42c576..3a0874c
Fast-forward
 index.html | 2 ++
 1 file changed, 2 insertions(+)

Mapapansin mo ang pariral na “fast-forward” sa merge na iyon. Dahil ang commit na C4 na itinuro ng hotfix na branch na iyong na-merge in ay direktang nauuna sa C2 na commit kung saan nandoon ka, ang Git ay simpleng ililipat ang pointer nang pasulong. Upang ipahayag iyon sa ibang paraan, kapag sinubukan mong i-merge ang isang commit sa isang pang commit na maaaring maabot sa pamamagitan ng pagsunod sa kasaysayan ng unang commit, ang Git ay pinapasimple ang mga bagay sa pamamagitan ng paglipat ng pointer nang pasulong dahil walang magkakaibang trabaho na sama-samang i-merge — ito ay tinatawag na isang “fast-forward.”

Ang iyong pagbabago ay nasa snapshot na ngayon ng commit na itinuro ng master na branch, at maaari mong i-deploy ang fix.

Ang `master` ay na-fast-forward sa `hotfix`.
Figure 22. Ang master ay na-fast-forward sa hotfix

Pagkatapos ma-deploy ang iyong sobrang importanteng pag-ayos, handa ka nang lumipat pabalik sa trabahong ginagawa mo dati bago ka naabala. Ngunit, una ay burahin mo ang hotfix na branch, dahil hindi mo na kailangan ito — ang master na branch ay nakaturo sa parehong lugar. Maaari mong burahin ito gamit ang -d na opsyon sa git branch:

$ git branch -d hotfix
Deleted branch hotfix (3a0874c).

Ngayon maaari ka nang lumipat pabalik sa iyong work-in-progress na branch sa isyu #53 at magpatuloy sa pagtrabaho nito.

$ git checkout iss53
Switched to branch "iss53"
$ vim index.html
$ git commit -a -m 'finished the new footer [issue 53]'
[iss53 ad82d7a] finished the new footer [issue 53]
1 file changed, 1 insertion(+)
Ang trabaho ay magpapatuloy sa `iss53`.
Figure 23. Ang trabaho ay magpapatuloy sa iss53

Mahalagang tandaan dito na ang trabaho na iyong ginawa sa iyong hotfix na branch ay hindi nilalaman sa mga file sa iyong iss53 na branch. Kung kailangan mong i-pull ito, maaari mong i-merge ang iyong master na branch sa iyong iss53 na branch sa pagpapatakbo ng git merge master, o maaari kang maghintay na pagsamahin ang mga pagbabagong iyon hanggang ikaw ay makapagpasya na i-pull ang iss53 na branch pabalik sa master mamaya.

Batayan ng Pag-merge

Mangyaring ikaw ay nakapagpasya na ang iyong isyu #53 na trabaho ay natapos at handa nang i-merge sa iyong master na branch. Upang magawa iyon, ime-merge mo ang iyong iss53 na branch sa master, masyadong katulad ng pag-merge mo sa iyong hotfix na branch kamakailan lamang. Ang kailangan mo lamang gawin ay i-check out ang branch na gusto mong i-merge at pagkatapos ay patakbuhin ang git merge na utos:

$ git checkout master
Switched to branch 'master'
$ git merge iss53
Merge made by the 'recursive' strategy.
index.html |    1 +
1 file changed, 1 insertion(+)

Ito ay mukhang medyo iba sa hotfix na merge na ginawa mo kamakailan lamang. Sa kasong ito, ang kasaysayan ng iyong pag-develop ay humiwalay mula sa ilang mas matandang punto. Dahil ang commit sa branch kung saan nandoon ka ay hindi isang direktang ninuno ng branch na iyong mini-merge, ang Git ay dapat gumawa ng ilang trabaho. Sa kasong ito, ang Git ay gagawa ng isang simpleng three-way na merge, gamit ang dalawang snapshot na itinuro ng mga dulo ng branch at ang karaniwang ninuno ng dalawa.

Tatlong mga snapshot na ginamit sa isang tipikal na merge.
Figure 24. Tatlong mga snapshot na ginamit sa isang tipikal na merge

Sa halip na ililipat lamang ang pointer ng branch nang pasulong, ang Git ay gagawa ng isang panibagong snapshot na nagreresulta mula sa three-way na merge na ito at awtomatikong bubuo ng isang panibagong commit na nakaturo nito. Ito ay tinutukoy bilang isang merge na commit, at ang espesyal nito ay mayroon itong higit pa sa isang magulang.

Isang merge na commmit.
Figure 25. Isang merge na commmit

Mahalagang pagtuunan ng pansin na tinutukoy ng Git ang pinakamabuti na karaniwang ninuno para gamitin sa merge base nito; ito ay iba sa mas matandang mga kasangkapan katulad ng CVS o Subversion (bago ang bersyon 1.5), kung saan ang developer na gumagawa ng merge ay kailangang malaman ang pinakamainam na merge base para sa sarili nila. Ginagawa nitong mas madali ang pag-merge sa Git kaysa sa mga ibang sistemang ito.

Ngayong ang iyong trabaho ay naka-merge na, wala ka nang higit pang kailangan para sa iss53 na branch. Maaari mo nang isara ang tiket sa iyong ticket-tracking na sistema, at burahin ang branch:

$ git branch -d iss53

Mga Pangunahing Salungatan sa Pag-Merge

Paminsan-minsan, ang prosesong ito ay hindi dadaloy ng maaayos. Kung binago mo ang parehong parte ng parehong file na nagkakaiba sa dalawang branch na iyong ime-merge pareho, ang Git ay hindi makakayang i-merge ang mga ito nang malinis. Kung ang iyong pag-ayos para sa isyu #53 ay nagbago ng parehong parte ng isang file bilang hotfix na branch, magkakaroon ka ng isang merge na salungatan na magmumukha katulad nito:

$ git merge iss53
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.

Ang Git ay hindi awtomatikong gumawa ng isang bagong merge na commmit. Ito ay sandaling tinigil ang proseso habang ikaw ay naglulutas ng mga salungatan. Kung gusto mong tingnan kung ano ang mga file an naka-unmerge sa anumang punto pagkatapos ng isang salungatan sa pag-merge, maaari mong patakbuhin ang git status:

$ git status
On branch master
You have unmerged paths.
  (fix conflicts and run "git commit")

Unmerged paths:
  (use "git add <file>..." to mark resolution)

    both modified:      index.html

no changes added to commit (use "git add" and/or "git commit -a")

Anuman ang mayroong mga salungatan sa pag-merge at hindi nalutas ay nakalista bilang naka-unmerge. Ang Git ay nagdaragdag ng pamantayan na mga marker para sa conflict-resolution sa mga file na mayroong mga salungatan, upang maaari mong manu-manong buksan ang mga ito at lutasin ang mga salungatang iyon. Ang iyong file ay naglalamang ng isang bahagi na nagmumukha katulad nito:

<<<<<<< HEAD:index.html
<div id="footer">contact : email.support@github.com</div>
=======
<div id="footer">
 please contact us at support@github.com
</div>
>>>>>>> iss53:index.html

Ang kahulugan nito ay ang bersyon sa HEAD (iyong master na branch, dahil iyon ang na-check out mo kapag nagpatakbo ka ng iyong merge na utos) ay ang tuktok na parte ng blokeng iyon (anuman na nasa itaas ng =======), habang ang bersyon sa iyong iss53 na branch ay nagmumukhang katulad sa lahat sa ibaba na parte. Upang malutas ang salungatan, kailangan mong alinmang pumili ng isang gilid o ang iba o sariling i-merge ang mga nilalaman. Halimbawa, ikaw ay maaaring maglutas ng salungatang ito sa pamamagitan ng pagpapalit ng buong bloke gamit nito:

<div id="footer">
please contact us at email.support@github.com
</div>

Ang resolusyong ito ay may maliliit na seksyon, at ang <<<<<<<, =======, at >>>>>>> na mga linya ay ganap na natanggal. Pagkatapos mong malutas ang bawat seksyon na mga ito sa bawat salungatang file, patakbuhin ang git add sa bawat file upang markahan bilang nalutas na. Ang pag-stage ng file ay nagmamarka nito bilang nalutas na sa Git.

Kung gusto mong gumamit ng isang grapikal na kasangkapan para sa paglutas ng mga isyu, maaari mong patakbuhin ang git mergetool, na nagpapagana ng isang angkop na biswal na merge na kasangkapan at ilalakad ka sa mga salungatan:

$ git mergetool

This message is displayed because 'merge.tool' is not configured.
See 'git mergetool --tool-help' or 'git help config' for more details.
'git mergetool' will now attempt to use one of the following tools:
opendiff kdiff3 tkdiff xxdiff meld tortoisemerge gvimdiff diffuse diffmerge ecmerge p4merge araxis bc3 codecompare vimdiff emerge
Merging:
index.html

Normal merge conflict for 'index.html':
  {local}: modified file
  {remote}: modified file
Hit return to start merge resolution tool (opendiff):

Kung gusto mong gumamit ng isang merge na kasangkapan maliban sa default (ang Git ay pumili ng opendiff sa kasong ito dahil ang utos ay napatakbo sa isang Mac), maaari mong tingnan lahat ang mga suportadong mga kasangkapan na nakalista sa tuktok pagkatapos ng “isa sa mga sumusunod na mga kasangkapan.” I-type lamang ang pangalan ng kasangkapan na mas gugustuhin mong gamitin.

Kung kailangan mo ng mas advance na mga kasangkapan para sa paglulutas ng nakakalitong mga salungatan sa pag-merge, nasasakop pa namin ang higit pa sa pag-merge sa Advanced na Pag-merge.

Pagkatapos mong lumabas sa merge na kasangkapan, ang Git ay tatanungin ka kung matagumpay ba ang pag-merge. Kung sasabihan mo ang iskrip na matagumpay, ito ay isi-stage ang file upang markahan ito bilang nalutas na para sa iyo. Maaari mong patakbuhin ang git status ulit para mapatunayan na ang lahat ng mga salungatan ay nalutas na:

$ git status
On branch master
All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)

Changes to be committed:

    modified:   index.html

Kung masaya ka na sa iyon, at mapatunayan mo na ang lahat ng may mga salungatan ay na-stage na, maaari mong i-type ang git commmit upang tapusin ang merge na commit. Ang mensahe ng commit na default ay magmumukha katulad nito:

Merge branch 'iss53'

Conflicts:
    index.html
#
# It looks like you may be committing a merge.
# If this is not correct, please remove the file
#	.git/MERGE_HEAD
# and try again.


# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# All conflicts fixed but you are still merging.
#
# Changes to be committed:
#	modified:   index.html
#

Kung sa tingin mong ito ay makakatulong sa iba na titingin sa merge na ito sa hinaharap, maaari mong baguhin ang mensahe ng commit na ito gamit ang mga detalye tungkol sa kung papaano mo nalutas ang merge at paliwanag kung bakit mo ginawa ang mga pagbabagong ginawa mo kung hindi halata ang mga ito.