-
1. Pagsisimula
-
2. Mga Pangunahing Kaalaman sa Git
-
3. Pag-branch ng Git
-
4. Git sa Server
- 4.1 Ang Mga Protokol
- 4.2 Pagkuha ng Git sa isang Server
- 4.3 Ang paglikha ng iyong Pampublikong Susi ng SSH
- 4.4 Pag-Setup ng Server
- 4.5 Git Daemon
- 4.6 Smart HTTP
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 Mga Opsyon ng Naka-host sa Third Party
- 4.10 Buod
-
5. Distributed Git
- 5.1 Distributed Workflows
- 5.2 Contributing to a Project
- 5.3 Maintaining a Project
- 5.4 Summary
-
6. GitHub
-
7. Mga Git na Kasangkapan
- 7.1 Pagpipili ng Rebisyon
- 7.2 Staging na Interactive
- 7.3 Pag-stash at Paglilinis
- 7.4 Pag-sign sa Iyong Trabaho
- 7.5 Paghahanap
- 7.6 Pagsulat muli ng Kasaysayan
- 7.7 Ang Reset Demystified
- 7.8 Advanced na Pag-merge
- 7.9 Ang Rerere
- 7.10 Pagdebug gamit ang Git
- 7.11 Mga Submodule
- 7.12 Pagbibigkis
- 7.13 Pagpapalit
- 7.14 Kredensyal na ImbakanCredential Storage
- 7.15 Buod
-
8. Pag-aangkop sa Sariling Pangangailagan ng Git
- 8.1 Kompigurasyon ng Git
- 8.2 Mga Katangian ng Git
- 8.3 Mga Hook ng Git
- 8.4 An Example Git-Enforced Policy
- 8.5 Buod
-
9. Ang Git at iba pang mga Sistema
- 9.1 Git bilang isang Kliyente
- 9.2 Paglilipat sa Git
- 9.3 Buod
-
10. Mga Panloob ng GIT
- 10.1 Plumbing and Porcelain
- 10.2 Git Objects
- 10.3 Git References
- 10.4 Packfiles
- 10.5 Ang Refspec
- 10.6 Transfer Protocols
- 10.7 Pagpapanatili At Pagbalik ng Datos
- 10.8 Mga Variable sa Kapaligiran
- 10.9 Buod
-
A1. Appendix A: Git in Other Environments
- A1.1 Grapikal Interfaces
- A1.2 Git in Visual Studio
- A1.3 Git sa Eclipse
- A1.4 Git in Bash
- A1.5 Git in Zsh
- A1.6 Git sa Powershell
- A1.7 Summary
-
A2. Appendix B: Pag-embed ng Git sa iyong Mga Aplikasyon
- A2.1 Command-line Git
- A2.2 Libgit2
- A2.3 JGit
-
A3. Appendix C: Mga Kautusan ng Git
- A3.1 Setup at Config
- A3.2 Pagkuha at Paglikha ng Mga Proyekto
- A3.3 Pangunahing Snapshotting
- A3.4 Branching at Merging
- A3.5 Pagbabahagi at Pagbabago ng mga Proyekto
- A3.6 Pagsisiyasat at Paghahambing
- A3.7 Debugging
- A3.8 Patching
- A3.9 Email
- A3.10 External Systems
- A3.11 Administration
- A3.12 Pagtutuberong mga Utos
3.6 Pag-branch ng Git - Pag-rebase
Pag-rebase
Sa Git, mayroong dalawang pangunahing mga paraan upang pagsamahin ang mga pagbabago mula sa isang branch patungo sa iba: ang merge
at ang rebase
. Sa seksyong ito matututo ka kung ano ang pag-rebase, paano ito gawin, bakit ito ay isang medyo kahanga-hangang kasangkapan, at sa anong kaso mo hindi gugustuhing gamitin ito.
Ang Pangunahing Rebase
Kung ikaw ay pupunta pabalik sa kamakailang halimbawa mula sa Batayan ng Pag-merge, maaari mong tingnan na nahiwalay mo ang iyong trabaho at gumawa ng mga commit sa dalawang magkaibang mga branch.
Ang pinakamadaling paraan upang mapagsama ang mga branch, bilang nasakop na natin, ay ang merge
na utos. Ito ay gumagawa ng isang three-way na merge sa pagitan ng dalawang pinakabagong mga snapshot ng branch (C3
at C4
) at ang pinakakamakailang karaniwang ninuno ng dalawa (C2
), kaya gumagawa ng isang panibagong snapshot (at commit).
Subalit, mayroong ibang paraan: maaari mong kunin ang patch ng pagbabago na napakilala sa C4
at ilapat muli ito sa itaas ng C3
. Sa Git, ito ay tinatawag na rebasing. Gamit ang rebase
na utos, maaari mong kunin ang lahat ng mga pagbabago na na-commit sa isang branch at i-replay ang mga ito sa iba pa.
Sa halimbawang ito, papatakbuhin mo ang sumusunod:
$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command
Gumagana ito sa pamamagitan ng pagpunta sa karaniwang ninuno ng dalawang mga branch (yung isa ay kung saan nandoon ka at yung isa ay kung saan ka magre-rebase), kukunin ang diff na napakilala sa bawat commit ng branch kung saan nandoon ka, isi-save ang mga diff na iyon sa pansamantalang mga file, iri-reset ang kasalukuyang branch sa parehong commit bilang branch na iyong iri-rebase, at sa huli ay ilalapat ang bawat pagbabago.
C4
patungo sa C3
Sa puntong ito, maaari kang pumunta pabalik sa master
na branch at gumawa ng fast-forward na merge.
$ git checkout master
$ git merge experiment
Ngayon, ang snapshot na itinuro ng C4'
ay eksaktong kapareho sa isa na itinuro ng C5
sa merge na halimbawa. Walang pagkakaiba sa resulta ng integrasyon, ngunit ang pag-rebase ay ginagawang mas malinis ang kasaysayan. Kung iyong susuriin ang log ng isang na-rebase na branch, magmumukha itong isang linear na kasaysayan: lumalabas na ang lahat ng trabaho ay nangyari na nakaserye, kahit ito ay orihinal na nangyari na nakahilera.
Kadalasan, gagawin mo ito upang siguraduhing ang iyong mga commit ay nalapat nang malinis sa isang remote na branch — marahil sa isang proyekto kung saan sinusubukan mong mag-ambag ngunit iyong hindi mo na pinapanatili. Sa kasong ito, gagawin mo ang iyong trabaho sa isang branch at pagkatapos ay iri-rebase ang iyong trabaho sa origin/master
kapag ikaw ay handa nang isumite ang iyong mga patch sa pangunahing proyekto. Sa paraan iyon, ang tagapanatili ay hindi na kailangang gumawa ng anumang pagsasama na trabaho — isang fast-forward o isang malinis na paglapat lamang.
Tandaan na ang snapshot na itinuro ng huling commit na nagtapos sa iyo, kung ito ay ang huli sa na-rebase na mga commit para sa isang rebase o ang huling merge na commit pagkatapos ng isang merge, ay ang parehong snapshot - ang kasaysayan lamang ang naiiba. Ang pag-rebase ay iri-replay ang mga pagbabago mula sa isang linya ng trabaho patungo sa iba sa pagkakaayos base sa kanilang pagpakilala, samantalang ang pag-merge ay kinukuha ang mga endpoint at sama-samang imi-merge ang mga ito.
Maraming Kagiliw-giliw na mga Rebase
Maaari ka ring magkaroon ng iyong rebase na replay sa anuman maliban sa rebase na target na branch. Gamitin ang isang kasaysayan katulad ng Isang kasaysayan na may isang paksa na naka-branch off sa ibang paksa na branch, bilang halimbawa. Ikaw ay nag-branch ng isang paksa na branch (server
) upang magdagdag ng ilang server-side na functionality sa iyong proyekto, at gumawa ng isang commit. Pagkatapos, ikaw ay nag-branch off nito upang gawin ang mga pagbabago sa client-side (client
) at nag-commit ng ilang beses. Sa wakas, ikaw ay bumalik sa iyong server na branch at gumawa ng ilang mga commit.
Ipagpalagay na ikaw na nakapagpasya na gusto mong i-merge ang iyong client-side na mga pagbabago sa iyong mainline para sa isang release, ngunit gusto mong pigilan ang mga pagbabago ng server-side hanggang ito ay mas lalo pang nasubukan. Maaari mong kunin ang mga pagbabago na wala sa server (C8
at C9
) at i-replay ang mga ito sa iyong master
na branch gamit ang --onto
na opsyon ng git rebase
:
$ git rebase --onto master server client
Ang ibig talagang sabihin nito ay, “Kunin ang client
na branch, alamin ang mga patch mula nung humiwalay ito mula sa server
na branch, at i-replay ang mga patch na ito sa client
na branch animo ito ay direktang nakabase sa master
na branch.” Ito ay medyo kumplikado, ngunit ang resulta ay talagang kamangha-mangha.
Ngayon maaari ka nang mag-fast-forward sa iyong master
na branch (tingnan ang Pag-fast-forward ng iyong master na branch upang isama ang mga pagbabago sa kliyente na branch):
$ git checkout master
$ git merge client
Sabihin nating ikaw ay nakapagpasyang mag-pull din sa iyong server na branch. Maaari mong i-rebase ang server na branch sa master
na branch nang hindi kailangang unang mag-check out nito sa pamamagitan ng pagpapatakbo ng git rebase <basebranch> <topicbranch>
— na nagchi-check out ng paksa na branch (sa kasong ito, server
) para sa iyo at iri-replay ito sa base na branch (master
):
$ git rebase master server
Ito ay iri-replay ang iyong server
na trabaho sa itaas ng iyong master
na trabaho, na ipinapakita sa Pag-rebase ng iyong server na branch sa itaas ng iyong master na branch.
Pagkatapos, maaari mong i-fast-forward ang base na branch (master
):
Then, you can fast-forward the base branch (master
):
$ git checkout master
$ git merge server
Maaari mong tanggalin ang client
at server
na mga branch dahil lahat ang trabaho ay napagsama-sama na at hindi mo na kailangan ang mga ito, iniiwan ang iyong kasaysayan para sa buong proseso na nagmumukhang katulad ng Huling kasaysayan ng commit:
$ git branch -d client
$ git branch -d server
Ang mga Panganib ng Pag-rebase
Ahh, ngunit ang kaligayahan ng pag-rebase ay mayroon ding kakulangan, na maaaring mabuo sa isang linya:
Huwag mag-rebase ng mga commit na umiiral sa labas ng iyong repositoryo.
Kung susundin mo ang patnubay na iyon, magiging maayos ka. Kung hindi, kasusuklaman ka ng mga tao, at kakamuhian ka ng iyong mga kaibigan at pamilya.
Kapag ikaw ay nag-rebase ng mga bagay, ikaw ay lumilisan sa umiiral na mga commit at gumagawa ng mga panibago na kahawig ngunit naiiba.
Kung magpu-push ka ng mga commit saanman at ang iba ay magpu-pull down ng mga ito at magbabase sa trabaho nito, at pagkatapos ay isusulat mo muli ang mga commit na iyon gamit ang git rebase
at i-push muli ang mga ito, ang iyong mga katulong ay kailangang mag merge muli ng kanilang trabaho at ang mga bagay ay magugulo kapag sinubukan mong mag-pull sa kanilang trabaho patungo pabalik sa iyo.
Tumingin tayo sa isang halimbawa kung papaano ang pag-rebase ng trabaho na iyong ginawang publiko ay maaaring magsanhi ng mga problema. Ipagpalagay na ikaw ay nag-clone mula sa isang sentral na server at pagkatapos ay gumawa ng ilang trabaho sa iyon. Ang iyong kasaysayan ng commit ay magmumukhang katulad nito:
Ngayon, may iba pang gumagawa ng higit pang trabaho na nagsasama ng isang merge, at nagpu-push ng trabahong iyon sa sentral na server. Kinuha mo ito at nag-merge ng bagong remote na branch sa iyong trabaho, ginagawang magkamukha nito ang iyong kasaysayan:
Susunod, ang tao na nag-push ng na-merge na trabaho ay nagpasyang bumalik at sa halip ay mag-rebase ng kanilang trabaho; gumawa sila ng isang git push --force
upang sapawan ang kasaysayan sa server. Ikaw ngayon ay nag-fetch mula sa server na iyon, hinihila pababa ang mga bagong commit.
Ngayon kayong dalawa ay nasa mahirap na kalagayan. Kung gagawa ka ng isang git pull
, ikaw ay lilikha ng isang merge na commit na naglalaman ng parehong mga linya ng kasaysayan, at ang iyong repositoryo ay magmumukhang katulad nito:
Kung magpapatakbo ka ng isang git log
kapag ang iyong kasaysayan ay magmumukhang katulad nito, makikita mo ang dalawang mga commit na mayroong parehong may-akda, petsa, at mensahe, na kung saan ay nakalilito.
At saka, kung ipu-push mo ang kasaysayang ito pabalik sa server, ipapakilala mo ulit ang lahat ng mga na-rebase na commit na iyon sa sentral na server, na kung saan ay tuluyan pang nakakalito sa mga tao.
Medyo ligtas magpalagay na ang ibang developer ay hindi gusto ang C4
at C6
sa kasaysayan; iyan ang dahilan kung bakit sila nag-rebase sa simula pa lang.
Mag-rebase Kung Ikaw ay Mag-rebase
Kung talagang natagpuan mo iyong sarili sa sitwasyong katulad nito, ang Git ay may ilang higit pang salamangka na maaaring makatulong sa iyo. Kung may tao sa iyong team na sapilitang nagpu-push ng mga pagbabago na nag-o-overwrite ng trabaho kung saan nakabase ang iyong mga ginawa, ang iyong hamon ay ang malaman kung ano ang sa iyo at kung ano ang nasulat muli nila.
Lumilitaw na sa karagdagan sa checksum ng commit SHA-1, ang Git ay nagkakalkula rin ng isang checksum na nakabase lamang sa patch na napakilala sa commit. Ito ay tinatawag na isang “patch-id”.
Kung ikaw ay magpu-pull down ng trabaho na muling isinulat at iri-rebase ito sa itaas ng bagong mga commit mula sa iyong kasosyo, ang Git ay kadalasang matagumpay na nalalaman kung ano ang katangi-tanging sa iyo at ilalapat ang mga ito pabalik sa itaas ng bagong branch.
Halimbawa, sa nakaraang sitwasyon, kung sa halip na gumawa ng isang merge kapag tayo ay nasa May isang tao na nagpu-push ng na-rebase na mga commit, iniiwanan ang mga commit kung saan mo binase ang iyong trabaho papatakbuhin natin ang git rebase teamone/master
, ang Git ay:
-
Tutukuyin kung anong trabaho ang katangi-tangi sa ating branch (C2, C3, C4, C6, C7)
-
Tutukuyin kung ano ang hindi merge na mga commit (C2, C3, C4)
-
Tutukuyin kung ano ang hindi naisulat muli sa target na branch (C2 at C3 lamang, dahil ang C4 ay kaparehong patch sa C4')
-
Ilalapat ang mga commit na iyon sa itaas ng
teamone/master
Kaya sa halip sa resulta na nakikita natin sa Ikaw ay muling nag-merge sa parehong trabaho patungo sa isang panibagong merge na commmit, tayo ay magtatapos na may bagay na mas katulad sa Pag-rebase sa itaas ng na-force-push na rebase ng trabaho.
Ito ay gumagana lamang kung ang C4 at C4' na ginawa ng iyong kasosyo ay halos eksaktong magkatugma na patch. Kung hindi ay ang rebase ay hindi makakapagsabi na ito ay isang kopya at magdaragdag ng ibang katulad ng C4 na patch (na marahil ay mabibigong malinis na maglapat, dahil ang mga pagbabago ay marahil nandoon na).
Maaari mo ring pasimplihin ito sa pamamagitan ng isang git pull --rebase
sa halip na isang normal na git pull
. O maaari mong manu-manong gawin ito gamit ang isang git fetch
na sinusundan ng isang git rebase teamone/master
sa kasong ito.
Kung ikaw ay gumagamit ng git pull
at gustong i---rebase
ang default, maaari mong itakda ang halaga ng pull.rebase
na config gamit ang kagaya ng git config --global pull.rebase true
.
Kung ituturing mo ang pag-rebase bilang isang paraan upang maglinis at magtrabaho sa mga commit bago mo i-push ang mga ito, at kung ikaw ay magri-rebase lamang ng mga commit na hindi pampublikong magagamit, ikaw ay magiging maayos lamang. Kung ikaw ay magri-rebase ng mga commit na pampublikong nai-push na, at ang mga tao ay bumabase ng kanilang trabaho sa mga commit na iyon, ikaw ay maaaring mapasabak sa isang nakakabigong panganib, at suklam ng iyong mga kasamahan sa koponan.
Kung ikaw o isang kasosyo ay nakatuklas na kinakailangan ito sa isang punto, siguraduhing ang lahat ay nakakaalam kung paano patakbuhin ang git pull --rebase
upang subukang mas pasimplehin pa ang sakit nito pagkatapos.
Rebase vs. Merge
Ngayong nakita mo na ang pag-rebase at pag-merge na kumikilos, baka ikaw ay nagtataka kung ano ang mas mabuti. Bago natin maaaring sagutin ito, umatras muna tayo at pag-usapan ang tungkol sa ibig sabihin ng kasaysayan.
Isang pananaw nito ay ang iyong kasaysayan ng commit sa repositoryo ay isang rekord kung ano ang tunay na nangyari. Ito ay isang makasaysayang dokumento, mahalaga sa sarili nitong karapatan, at hindi dapat mabago. Mula sa anggulong ito, ang pagbabago sa kasaysayan ng commit ay halos lapastangan sa diyos; ikaw ay nagsisinungaling tungkol sa kung ano ang tunay na naganap. Kaya ano kung mayroong isang magulong serye ng merge na mga commit? Iyon ang nangyari, at ang repositoryo ay kailangang i-preserba iyon para sa angkan.
Ang humahadlang na pananaw ay ang kasaysayan ng commit ay ang istorya kung papaano nagawa ang iyong proyekto. Hindi mo iaambag ang unang draft ng isang aklat, at ang manwal para sa kung papaano panatilihin ang iyong software ay nararapat na ingatan ang pag-edit. Ito ang kampo na gumagamit ng mga kasangkapan katulad ng rebase at filter-branch upang magtalakay sa istorya sa paraan na pinakamainam para sa mga mambabasa sa hinaharap.
Ngayon, sa tanong kung alin sa pag-merge o pag-rebase ang mas mabuti: sana makita mo na ito ay hindi ganoon ka simple. Ang Git ay isang makapangyarihan na kasangkapan, at nagpapahintulot sa iyo upang gumawa ng maraming mga bagay at gamit ang iyong kasaysayan, ngunit bawat koponan at bawat proyekto ay magkakaiba. Ngayon na alam mo na kung paano gumagana ang dalawang bagay na ito, nakasalalay sa iyo na magpasya kung ano ang pinakamainam para sa iyong partikular na sitwasyon.
Sa karaniwan ang paraan upang makakuha ng pinakamabuti sa dalawang mundo ay ang pag-rebase ng mga lokal na pagbabago na ginawa mo ngunit hindi pa naibahagi bago mo i-push ang mga ito upang linisin ang iyong istorya, ngunit huwag mag-rebase ng kahit ano na na-push mo kahit saan.