-
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
7.8 Mga Git na Kasangkapan - Advanced na Pag-merge
Advanced na Pag-merge
Ang pag-merge sa Git ay karaniwang medyo madali. Dahil ang Git ay nagagawa nito ipadali ang pag-merge sa ibang branch ng maraming beses, ito ay nangangahulugan na maaari ka na merong isang matagal nang buhay na branch ngunit maaari mong panatilihin ang pinakabago habang ikaw ay gumagamit, paglutas ng maliit na mga kasalungat ng madalas, sa halip na mabigla ng isang napakalaking salungat sa katapusan ng serye.
Gayunpaman, minsan nakakalito ang mga salungatan na magaganap. Di tulad ng ibang mga bersyon na kontrol na mga sistema, ang Git ay hindi susubok upang maging sobrang matalino tungkol sa pagsama ng pagsasalungatan na resolusyon. Ang pilisopiya ng Git ay dapat maging talino tungkol sa pagtukoy kapag ang isang merge na resolusyon ay hindi malabo, ngunit kung may isang salungat, hindi ito sinubukan na maging matalino tungkol sa awtomatikong palutas nito. Samakatuwid, kung ikaw ay naghintay nang sobrang tagal upang i-merge ang dalawang branch na mabilis na nagbabagu-bago, maaari kang magpatakbo ng ilang mga isyu.
Sa seksyon na ito, kami ay magpapatuloy kung ano ang mga maaaring isyu at anong mga kasangkapan na nagbibigay tulong upang panghawakan ang mga ito na mas madayang mga sitwasyon. At saka tatalakayin din natin ang iba’t iba, na hindi pamantayan na mga uri ng mga merge na maaari mong gawin, pati na rin makita kung paano umatras sa mga merge na iyong nagawa.
Pag-merge sa mga Kasalungat
Habang nasakop natin ang maraming mga batayan sa paglulutas ng merge na mga salungat sa Mga Pangunahing Salungatan sa Pag-Merge, para sa higit na kumplikado na mga salungat, Ang Git ay nagbibigay na ilang mga kasangkapan para tulungan ka na tingnan kung ano ang nangyayari at kung paano mas mahusay na makitungo sa mga salungat.
Una sa lahat, kung sa lahat ay posible, subukan na siguraduhin na ang iyong tinatrabahong direktoryo ay malinis bago magsagawa ng merge na maaaring magkakaroon ng mga salungat. Kung merong kang trabaho na nasa proseso, alinmang i-commit ito sa isang pansamantalang branch o itago ito. Ginagawa ito nito para maka-undo ka ng anumang bagay na sinubukan mo dito. Kung meron kang hindi na-save na mga pagbabago sa iyong tintrabahong direktoryo kapag sinubukan mong i-merge, ilan sa mga tip na ito ay tumutulong sayo na mawala ang trabahong iyon.
Tingnan nating mabuti ang pinakasimpleng halimbawa. Mayroon tayong isang sobrang simple na Ruby file na nagpri-print ng hello world.
#! /usr/bin/env ruby
def hello
puts 'hello world'
end
hello()
Sa repositoryo natin, tayo ay lilikha ng isang bagong branch na tinatawag na whitespace
at magpatuloy upang baguhin ang lahat na nagtatapos sa linyang Unix hanggang sa nagtatapos sa linyang DOS, na mahalagang nagbabago bawat linya sa file, pero basta may whitespace.
Then we change the line “hello world” to “hello mundo”.
$ git checkout -b whitespace
Switched to a new branch 'whitespace'
$ unix2dos hello.rb
unix2dos: converting file hello.rb to DOS format ...
$ git commit -am 'converted hello.rb to DOS'
[whitespace 3270f76] converted hello.rb to DOS
1 file changed, 7 insertions(+), 7 deletions(-)
$ vim hello.rb
$ git diff -b
diff --git a/hello.rb b/hello.rb
index ac51efd..e85207e 100755
--- a/hello.rb
+++ b/hello.rb
@@ -1,7 +1,7 @@
#! /usr/bin/env ruby
def hello
- puts 'hello world'
+ puts 'hello mundo'^M
end
hello()
$ git commit -am 'hello mundo change'
[whitespace 6d338d2] hello mundo change
1 file changed, 1 insertion(+), 1 deletion(-)
Ngayon tayo at lilipat pabalik sa ating master
na branch at magdagdag ng maraming dokumentasyon para sa function.
$ git checkout master
Switched to branch 'master'
$ vim hello.rb
$ git diff
diff --git a/hello.rb b/hello.rb
index ac51efd..36c06c8 100755
--- a/hello.rb
+++ b/hello.rb
@@ -1,5 +1,6 @@
#! /usr/bin/env ruby
+# prints out a greeting
def hello
puts 'hello world'
end
$ git commit -am 'document the function'
[master bec6336] document the function
1 file changed, 1 insertion(+)
Ngayon ay sinusubukan aming na i-merge sa ating whitespace
na branch at makakuha tayo ng mga salungat dahil sa whitespace na mga pagbabago.
$ git merge whitespace
Auto-merging hello.rb
CONFLICT (content): Merge conflict in hello.rb
Automatic merge failed; fix conflicts and then commit the result.
Pag-abort ng Merge
Tayo ngayon ay maroon nang ilang mga opsyon.
Una, talakayin natin kung papaano makalabas sa sitwasyon na ito.
Kung sasabihin mo na ikaw ay hindi umaasa ng mga salungat at hindi gusto ang medyong pakikitungo sa sitwasyon, maaari kang hindi magpatuloy sa pag-merge ng git merge --abort
.
$ git status -sb
## master
UU hello.rb
$ git merge --abort
$ git status -sb
## master
Ang git merge --abort
na opsyon na susubukang ibalik muli sa estado bago magpatakbo ng merge.
Ang tanging mga kaso na kung saan ay hindi perpektong makagawa kung ito ay hindi naitago, ang mga hindi nai-commit na mga pagbabago sa iyong tinatrabahong direktoryo kapag pinatakbo mo ito, kung hindi man ay dapat itong gumana ng maayos.
Para sa kadahilanan na gusto mo lang magsimulang muli, maaari ka ding magpatakbo ng git reset --hard HEAD
, at ang iyong repositoryo ay babalik sa huling na-commit na estado.
Tandaan na anumang hindi nai-commit na trabaho ay mawawala, kaya siguraduhin mo ang anumang pagbabago.
Hindi pinansin na Whitespace
Sa ganitong partikular na kaso, ang mga salungat ay may kaugnay sa whitespace. Alam natin ito dahil ang kaso ay simple, ngunit ito ay medyo madali rin na sabihin sa totoong mga kaso kapag tiningnan ang salungat dahil sa bawat linya ay inalis sa isang banda at dinagdag uli sa iba. Bilang default, ang Git ay nakakakita ng lahat na ito na mga linya bilang nabago, kaya ito ay hindi ma-merge ang mga file.
Ang default na diskarte ng pag-merge ay bagaman maaaring tumanggap ng maraming mga argumento, at ilang sa kanila ay tungkol sa maayos na pagbalewala ng mga pagbabago sa whitespace.
Kung ikaw ay makakita na merong kang maraming mga isyu sa whitespace sa isang merge, maaari mong itigil ito at ulitin uli, sa ngayon may -Xignore-all-space
o -Xignore-space-change
.
Ang unang opsyon ay nagbabalewala sa whitespace na ganap kung nagkukumpara ng mga linya, ang pangalawa ay nagtuturing sa sunod-sunod sa isa o higit na whitespace na mga karaker bilang katumbas.
$ git merge -Xignore-space-change whitespace
Auto-merging hello.rb
Merge made by the 'recursive' strategy.
hello.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Dahil sa kasong ito, ang aktwal na pagbabago ng file ay hindi nagkakasalungat, na kapag babalewalain ang whitespace na mga pagbabago, ang lahat ay magme-merge na okey lang.
Ito ay isang nagliligtas ng buhay kung ikaw ay may isang tao sa iyong koponan na gusto na paminsan-minsan na mag-reformat ng lahat ng bagay mula sa mga space hanggang sa mga tab o baliktad.
Manual File Re-merging
Kahit na humahawak ang Git sa whitespace pre-processing ng mabuti, may iba pang mga uri ng mga pagbabago na marahil hindi mahawakan ng awtomatiko, ngunit ay naka scriptable na mga pag-aayos. Bilang isang halimbawa, magpanggap tayo na ang Git ay hindi makahawak ng binago na whitespace at kailangan nating gawin ito sa pamamagitan ng ating mga kamay.
Ano talaga ang kailangan nating gawin ay ang patakbuhin ang file na sinusubukan nating i-merge sa pamamagitan ng isang dos2unix
na programa bago sinusubukan ang aktwal file na nai-merge.
Kaya paano natin ito gawin?
Una, kailangan natin pumunta sa merge na salungat na estado. Pagkatapos ay gusto nating kunin ang mga kopya sa aking bersyon sa file, ang kanilang bersyon(mula sa branch kami ay nagme-merge) at ang karaniwang bersyon (mula sa kung saang magkabilang panig na na-branch off). Pagkatapos gusto nating ayusin ng maaga sa kanilang panig o sa aming panig at subukang muli ang pag-merge muli para sa solong file lamang.
Pagkuha ng tatlong mga bersyon ng file ay talagang medyo madali.
Ang Git ay nag-iipon ng lahat ng mga bersyon na ito sa index sa ilalim ng “stages” na ang bawat isa ay may mga numero na nag-uugnay sa kanila.
Ang Stage 1 ay isang pangkaraniwang ninuno, ang stage 2 ay iyong bersyon at stage 3 ay mula sa MERGE_HEAD
, ang bersyon na iyong i-merge sa (“theirs”).
Maaari mong kunin ang isang kopya sa bawat bersyon na ito sa sumasalungat na file na may git show
na utos at isang espesyal na syntax.
$ git show :1:hello.rb > hello.common.rb
$ git show :2:hello.rb > hello.ours.rb
$ git show :3:hello.rb > hello.theirs.rb
Kung gusto mong makakuha ng isang maliit na mas hard core, maaari mo ding gamitn ang ls-files -u
na plumbing na utos command para makuha ang aktwal na SHA-1s sa Git blobs para sa bawat mga file na ito.
$ git ls-files -u
100755 ac51efdc3df4f4fd328d1a02ad05331d8e2c9111 1 hello.rb
100755 36c06c8752c78d2aff89571132f3bf7841a7b5c3 2 hello.rb
100755 e85207e04dfdd5eb0a1e9febbc67fd837c44a1cd 3 hello.rb
Ang :1:hello.rb
ay isa lamang shorthand para sa pagtingin na sa blob SHA-1.
Ngayon na mayroon kaming laman sa lahat ng tatlong mga stage sa aming tinatrabahong direktoryo, maaari nating mano-mano na ayusin ang kanilang aayusin na whitespace na isyu at i-merge uli ang file na may hindi gaaanong kilala git merge-file
na utos na ginagawa lamang iyon.
$ dos2unix hello.theirs.rb
dos2unix: converting file hello.theirs.rb to Unix format ...
$ git merge-file -p \
hello.ours.rb hello.common.rb hello.theirs.rb > hello.rb
$ git diff -b
diff --cc hello.rb
index 36c06c8,e85207e..0000000
--- a/hello.rb
+++ b/hello.rb
@@@ -1,8 -1,7 +1,8 @@@
#! /usr/bin/env ruby
+# prints out a greeting
def hello
- puts 'hello world'
+ puts 'hello mundo'
end
hello()
Mula rito kami ay mabuting naka-merge sa file.
Sa katunayan, talagang gumagana itong mas mahusay kaysa sa ignore-space-change
na opsyon dahil ito talaga ay nag-aayos sa pagbabago ng whitespace bago nai-merge sa halip na balewalain ang mga ito.
Ang nasa ignore-space-change
na merge, talagang natapos na kami na may ilang linya na may nagtatapos na DOS na linya, gumgawa ng mga bagay na magkahalo.
Kung gusto mong makakuha ng isang ideya bago ang pagwawakas ng commit na ito tungkol sa kung ano ang tunay na nabago sa pagitan ng isang panig o ang iba, maaari mong tanungin ang git diff
para ikumpara kung ano ang nasa iyong tinatrabahong direktoryo na malapit mo nang i-commit bilang resulta sa pag-merge ng anumang mga stage na ito.
Talakayin natin ang lahat na ito.
Para ikumpara ang iyong resulta sa kung ano ang nasa iyong branch bago ang merge, sa ibang salita, para tingnan kung ano ang naipakilala na nai-merge, maaari kang magpatakbo ng git diff --ours
$ git diff --ours
* Unmerged path hello.rb
diff --git a/hello.rb b/hello.rb
index 36c06c8..44d0a25 100755
--- a/hello.rb
+++ b/hello.rb
@@ -2,7 +2,7 @@
# prints out a greeting
def hello
- puts 'hello world'
+ puts 'hello mundo'
end
hello()
Kaya narito kami para madaling makita kung anong ang nangyari sa ating branch, na kung ano talaga ang ipinakilala sa file sa pag-merge nito, ay nagbabago sa solong linya.
Kung gusto nating tingnan ang resulta sa merge differed mula sa kung ano ang nasa kanilang panig, maaari kang magpatakbo ng git diff --theirs
.
Dito sa at ang sumusunod na halimbawa, kailangan nating gamitin ang -b
upang alisin ang whitespace dahil ikukumpara natin ito kung ano ang nasa Git, hindi ang ating nalinis na hello.theirs.rb
na file.
$ git diff --theirs -b
* Unmerged path hello.rb
diff --git a/hello.rb b/hello.rb
index e85207e..44d0a25 100755
--- a/hello.rb
+++ b/hello.rb
@@ -1,5 +1,6 @@
#! /usr/bin/env ruby
+# prints out a greeting
def hello
puts 'hello mundo'
end
Sa wakas, makikita mo kung paano ang file nagbago mula magkabilang panig sa git diff --base
.
$ git diff --base -b
* Unmerged path hello.rb
diff --git a/hello.rb b/hello.rb
index ac51efd..44d0a25 100755
--- a/hello.rb
+++ b/hello.rb
@@ -1,7 +1,8 @@
#! /usr/bin/env ruby
+# prints out a greeting
def hello
- puts 'hello world'
+ puts 'hello mundo'
end
hello()
Mula rito pwede nating gamitin ang git clean
na utos upang malinis ang dagdag na mga file na ginawa natin upang gawin ang manu-manong pag-merge ngunit hindi na kinakailangan.
$ git clean -f
Removing hello.common.rb
Removing hello.ours.rb
Removing hello.theirs.rb
Sinusuring ang mga Salungat
Marahil hindi tayo masaya sa resolusyon sa puntong ito para sa ilang kadahilanan, o maaaring mano-manong pag-edit sa isa o kapwa panig na hindi pa rin gumagana ng maayos at kakailanganin ng mas maraming konteksto.
Tayo ay magbago ng halimbawa ng kaunti. Para sa halimbawa na ito, mayroon tayong dalawang matagal na mga branch na ang bawat isa ay may ilang mga commit sa kanila ngunit lumikha ng isang lehitimong nilalaman na sumalungat kapag nai-merge.
$ git log --graph --oneline --decorate --all
* f1270f7 (HEAD, master) update README
* 9af9d3b add a README
* 694971d update phrase to hola world
| * e3eb223 (mundo) add more tests
| * 7cff591 add testing script
| * c3ffff1 changed text to hello mundo
|/
* b7dcc89 initial hello world code
Kapag meron ka nang tatlong natatanging mga commit na nabuhay lamang sa master
na branch at tatlong iba pa na nabuhay sa mundo
na branch.
Kung subukan natin i-merge sa mundo
na branch, makakuha tayo ng pagsasalungat.
$ git merge mundo
Auto-merging hello.rb
CONFLICT (content): Merge conflict in hello.rb
Automatic merge failed; fix conflicts and then commit the result.
Gusto namin tingnan kung ano ang salungat sa merge. Kung buksan natin ang file, makikita natin ang ibang bagay na tulad nito:
#! /usr/bin/env ruby
def hello
<<<<<<< HEAD
puts 'hola world'
=======
puts 'hello mundo'
>>>>>>> mundo
end
hello()
Bawat panig sa merge ay nagdaragdag ng nilalaman sa file na ito, ngunit marami sa mga commit na nagbago sa file sa parehong lugar na sanhi sa pagkasalungat nito.
Talakayin natin ang karamihan sa mga kasangkapan na sa ngayon ay alam mo na iyong magagamit upang malaman kung papaano ang pagkasalungat ay dumating. Marahil ito ay hindi halata kung gaano ka eksakto na dapat mong ayusin ang salungat. Kailangan mo ng maraming konteksto.
Isang matulungin na kasangkapan ay ang git checkout
kasama ang ‘--conflict’ na opsyon.
Ito ay mag-checkout muli muli sa file at papalitan ang salungat na merge na mga marka.
Maaari itong makakatulong kung gusto mong i-reset ang mga marker at subukan na malutas silang muli.
Maaari mong ipasa ang --conflict
alinman diff3
o merge
(kung saan ay ang default).
Kung ipapasa mo ito sa diff3
, ang Git ay gagamit ng isang bahagyang bersyon sa salungat na mga marka , di lamang nagbibigay sayo ng “ours” at “theirs” na mga bersyon, ngunit ang “base” din na bersyon na nasa linya upang magbigyan ka ng maraming konteksto.
$ git checkout --conflict=diff3 hello.rb
Sa sandaling patakbuhin natin yan, ang file ay kamukha nito sa halip:
#! /usr/bin/env ruby
def hello
<<<<<<< ours
puts 'hola world'
||||||| base
puts 'hello world'
=======
puts 'hello mundo'
>>>>>>> theirs
end
hello()
Kung gusto mo ang format na ito, maaari kang magtakda nito bilang default para sa hinaharap na merge na mga salungat sa pamamagitan ng pagtatakda ng merge.conflictstyle
at pagtatakda sa diff3
.
$ git config --global merge.conflictstyle diff3
Ang git checkout
na utos ay maaari ding kumuha ng --ours
at --theirs
na mga opsyon, na kung saan ay maaaring maging isang tunay na mabilis na paraan sa pagpili pa lamang alinman sa isang panig o sa iba na hindi naka merge sa mga bagay sa lahat.
Ito ay maaaring maging partikular na kapaki-pakinabang para sa mga salungat na mga binary file na kung saan maaari ka lamang pumili ng isang panig, o kung saan gusto lamang i-merge ang tiyak na mga file mula sa ibang branch - maaari mo ding gawin ang pag-merge at pagkatapos i-checkout tiyak na mga file mula sa isang panig o sa iba bago mag-commit.
Pag-merge ng Log
Ang kapaki-pakinabang na kasangkapan kapag naglutas ng merge na mga salungat ay ang git log
.
Ito ay nakakatulong sayo na kunin ang konteksto na sa kung ano ang maaaring maiiambag sa mga salungat.
Pagrepaso nang kaunti sa kasaysayan para tandaan kung bakit ang dalawang mga linya sa development na hinahawakan natin sa parehong nakakatulong minsan.
Para makakuha ng buong listahan sa lahat ng natatanging mga commit na nakasali sa alinmang branch na sangkot sa merge na ito, maaari nating gamitin ang “triple dot” na syntax na natutunan natin sa Triple na Dot.
$ git log --oneline --left-right HEAD...MERGE_HEAD
< f1270f7 update README
< 9af9d3b add a README
< 694971d update phrase to hola world
> e3eb223 add more tests
> 7cff591 add testing script
> c3ffff1 changed text to hello mundo
Iyan ay magandang listahan sa anim na kabuuang mga commit na kasangkot, pati na rin kung aling linya sa development para sa bawat commit na nangyayari.
Maaari tayong higit pa na magpasimple upang bigyan ng mas tiyak na konteksto.
Kung idagdag natin ang --merge
na opsyon sa git log
, ito ay nagpapakita lamang ng mga commit alinmang panig sa merge na nakahawak ng isang file na kasalukuyang may na salungat.
$ git log --oneline --left-right --merge
< 694971d update phrase to hola world
> c3ffff1 changed text to hello mundo
Kung nagpapatakbo ka gamit ang -p
na opsyon na sa halip, ikaw ay makakuha lamang ng diffs sa file na nagtatapos ng pagkasalungat.
Ito ay maaaring talagang kapaki-pakinabang sa mabilis na pagbibigay sayo ng konteksto na kailangan mo ng tulong na maunawaan kung bakit isang bagay ang mga kasalungat at kung papaano mas matalinong malutas ito.
Pinagsamang Diff na Format
Dahil ang mga Git ay nag-stage ng anumang mga resulta ng merge na matagumpay, kapag pinatakbo mo ang git diff
habang nasa pagkasalungat na merge na estado, ikaw ay makakuha lamang ng kung ano ang kasalukuyang nasa pagkasalungat.
Maaari itong matulungin upang makita kung ano ang hindi pa nalutas.
Kapag pinatakbo mo ang git diff
direkta matapos ang isang merge na salungat, ito ay nagbibigay ng impormasyon na sa halip ay natatanging diff output na format.
$ git diff
diff --cc hello.rb
index 0399cd5,59727f0..0000000
--- a/hello.rb
+++ b/hello.rb
@@@ -1,7 -1,7 +1,11 @@@
#! /usr/bin/env ruby
def hello
++<<<<<<< HEAD
+ puts 'hola world'
++=======
+ puts 'hello mundo'
++>>>>>>> mundo
end
hello()
Ang format ay tinatawag na “Combined Diff” at nagbibigay sa iyo ng dalawang mga column ng datos sa susunod sa bawat linya. Ang unang column ay nagpapakita sa iyo kung ang linya ay iba (nadagdag o inalis) sa pagitan ng “ours” na branch at ang file sa iyong tinatrabahong direktoryo at ang pangalawang column ay gagawa pareho sa pagitan ng “theirs” na branch at ang iyong tinatrabahong direktoryo na kopya.
Kaya sa halimbawang iyon ay makikita mo na ang <<<<<<<
and >>>>>>>
na mga linya ay nasa tinatrabahong kopya ngunit ay hindi alinman na panig sa merge.
Ito ay may katuturan dahil sa ang merge na kasangkapan ay natigil nila na para doon sa susunod na conteksto natin, ngunit inaasahan namin na maalis sila.
Kung lutasin natin ang salungat at ipatakbo ang git diff
muli, makikita natin ang parehong bagay, ngunit ito ay medyo mas magagamit.
$ vim hello.rb
$ git diff
diff --cc hello.rb
index 0399cd5,59727f0..0000000
--- a/hello.rb
+++ b/hello.rb
@@@ -1,7 -1,7 +1,7 @@@
#! /usr/bin/env ruby
def hello
- puts 'hola world'
- puts 'hello mundo'
++ puts 'hola mundo'
end
hello()
Ito ay nagpapakita na ang “hola world” ay nasa iyong panig ngunit wala sa tinatrabahong kopya, na ang “hello mundo” ay nasa kanilang panig ngunit wala sa tinatrabahong kopya at sa wakas na “hola mundo” ay wala sa magkabilang panig ngunit ngayon ay nasa tinatrabahong kopya. Ito ay maaaring magagamit sa pagsusuri bago ang pag-commit sa resolusyon.
Maaari kang makakuha din nito mula sa git log
para sa anumang merge upang makita kung paano nalutas pagkatapos sa katotohanan.
Ang Git ay mag-a-output ng ganitong format kung magpatakbo ka ng git show
sa isang merge commit, o kung ikaw ay magdagdag ng --cc
na opsyon sa isang git log -p
(na sa pamamagitan ng default lamang ay nagpapakita ng mga patch para sa non-merge na mga commit).
$ git log --cc -p -1
commit 14f41939956d80b9e17bb8721354c33f8d5b5a79
Merge: f1270f7 e3eb223
Author: Scott Chacon <schacon@gmail.com>
Date: Fri Sep 19 18:14:49 2014 +0200
Merge branch 'mundo'
Conflicts:
hello.rb
diff --cc hello.rb
index 0399cd5,59727f0..e1d0799
--- a/hello.rb
+++ b/hello.rb
@@@ -1,7 -1,7 +1,7 @@@
#! /usr/bin/env ruby
def hello
- puts 'hola world'
- puts 'hello mundo'
++ puts 'hola mundo'
end
hello()
Pag-undo sa mga Merge
Ngayon na alam mo na kung papaano maglikha ng isang merge commit, malamang ikaw ay gagawa ng pagkakamali. Isa sa mga dakilang mga bagay tungkol sa tinatrabaho gamit ang Git ay ok lang na makagawa ng mga pagkakamali, dahil ito ay posible (at sa maraming mga kaso na madali) sa pag-ayos nila.
Merge commits are no different.
Sabihin mo na ikaw ay nagsimula sa pagtrabaho sa isang topic na branch, aksidenteng na-merge mo ito sa master
, at ngayon ang iyong commit na kasaysayan ay ganito na ang hitsura:
Mayroong dalawang paraan upang lumapit sa ganitong problema, depende sa ano ang iyong ninanais na kinalalabasan.
Ayusin ang mga reperensiya
Kung ang hindi gustong merge commit ay umiiral na lamang sa iyong lokal na repositoryo, ang pinakamadali at pinakamahusay na solusyon ay ang ilipat ang mga branch upang sila ay nagtuturo kung saan gusto mo sila.
Sa maraming mga kaso, kung ikaw ay sumusunod sa maling git merge
na may git reset --hard HEAD~
, ito ay nagre-reset sa mga punto ng branch para magmukha silang ganito:
git reset --hard HEAD~
Tinatalakay namin ang reset
na balik sa Ang Reset Demystified, kaya ito ay hindi napakahirap na malaman kung ano nangyayari dito.
Narito ang isang mabilis na refresher: reset --hard
kadalasang napupunta sa tatlong paraan:
-
Igalaw ang branch HEAD na mga puntos sa. sa kasong ito, gusto naming ilipat ang
master
sa kung saan ito ay nating na merge commit (C6
). -
Gawin ang index na kamukha ng HEAD.
-
Gawin ang tinatrabahong direktoryo na kamukha ng index.
Ang kakulangan sa diskarteng ito ay ang kanyang sinusulatang muli na kasaysayan, na maaaring maging problema na may isang ibinabahaging direktoryo.
Tingnan ang Ang mga Panganib ng Pag-rebase para sa marami na mga pwedeng mangyari; ang maikling bersyon ay kung ang ibang tao ay mayroong mga commit na iyong sinusulatang muli, dapat mong marahil iwasan ang reset
.
Ang pamamaraan na ito ay hindi rin gagana kung ang ibang mga anumang commit ay nalikha mula nang na-merge; paglilipat sa mga ref ay epektibong mawawala ang mga pagbabago na iyon.
Ibaliktad ang commit
Kung ang paglilipat ng branch na mga punto sa paligid ay hindi gagana para sa iyo, Ang Git ay nagbibigay sayo ng opsyon sa paggawa ng isang bagong commit na nagbabawal sa lahat ng mga pagbabago sa isang umiireal na. Ang Git ay tumatawag sa operasyon na ito ang “revert”, at sa partikular na sitwasyon na ito, gusto mong itong tumawag ng katulad nito:
$ git revert -m 1 HEAD
[master b1d8379] Revert "Merge branch 'topic'"
Ang -m 1
na flag ay nagpapahiwatig kung aling magulang ang “mainline” at dapat manatili.
Kapag ikaw ay tumatawag ng merge sa HEAD
(git merge topic
), ang bagong commit ay mayroong dalawang magulang: ang pinaka una ay HEAD
(C6
), at ang pangalawa ay ang tip sa branch na pinagsama sa (C4
).
Sa kasong ito, gusto natin na pawalang-bisa ang lahat na pagbabago na ipinakilala sa pamamagitan ng pag-merge sa magulang #2 (C4
), habang pinapanatili ang lahat ng mga nilalaman mula sa magulang #1 (C6
).
Ang kasaysayan na may bumabalik na commit ay ganito ang hitsura nito:
git revert -m 1
Ang bagong commit ^M
ay may eksaktong parehong mga nilalaman bilang C6
, kaya nagsisimula mula dito na ito ay parang na-merge na hindi nangyari, maliban na ang ngayon-hindi na merge na mga commit ay nandiyan pa rin sa kasaysayan ni HEAD
.
Ang Git ay malilito kung ikaw ay sumubok sa pag-merge sa topic
sa master
muli:
$ git merge topic
Already up-to-date.
Walang anumang sa topic
na hindi pa naabot mula sa master
.
Kung ano ang mas masahol, kung ikaw ay magdagdag sa topic
at i-merge muli, Ang Git ay magdadala ng mga pagbabago dahil sa reverted na merge:
Ang pinakamahusay na paraan ay ang pag un-revert sa orihinal na merge, mula ngayon gusto mong dalhin ang mga pagbabago na iyong na-revert , pagkatapos lumikha ng isang bagong merge commit:
$ git revert ^M
[master 09f0126] Revert "Revert "Merge branch 'topic'""
$ git merge topic
Sa halimbawa na ito, M
at ^M
ay kinansela.
Ang ^^M
ay epektibong nag-merge sa mga pagbabago mula sa C3
at C4
, at C8
na mga merge sa pagbabago mula C7
, kaya ngayon ang topic
ay ganap na na-merge.
Ibang mga Uri ng mga Merge
Sa ngayon natalakay natin ang karaniwang na merge sa dalawang mga branch, karaniwang hinahawakan na may isang tinatawag na “recursive” na diskarte ng pag-merge. May ibang paraan sa pag-merge ng mga branch gayunpaman. Talakayin natin ang ilan sa kanila ng mabilis.
Amin o Kanilang Kagustuhan
Una sa lahat, may isang pang kapaki-pakinabang na bagay na maaari nating gawin sa normal na “recursive” na mode sa pag-merge.
Nakikita na natin ang ignore-all-space
at ignore-space-change
na mga opsyon na kung saan ay dumadaan sa isang -X
ngunit maaari din naming sabihin kay Git na paboran ang isang panig o ang iba kapag ito ay nakakita ng isang salungat.
Bilang default, kapag ang Git ay nakakita ng isang salungat sa pagitan ng dalawang mga branch na na-merge, ito ay idinaragdag ang merge na kasalungat na mga marka sa iyong code at markahan ang file bilang salungat at hayaan ka na malutas ito.
Kung nais mong mas gusto para sa Git upang pumili lamang ng isang partikular na panig at huwag pansinin ang ibang panig na sa halip ng pinapayagan kang mag-manu-mano na resulbahin ang salungat, maaari mong ipasa ang merge
na utos alinman sa isang -Xours
o -Xtheirs
.
Kung ang Git ay nakakita nito, ito ay hindi nagdagdag ng salungat na mga marka. Anumang kaibahan na pwedeng ma-merge, ito ay ma-merge. Anumang mga pagkakaiba na magkasalungat, ito ay pipili lang ng panig na tinutukoy mo nang buo, kabilang ang binary na mga file.
Kung babalik tayo sa “hello world” na halimbawa na ginagamit natin noon, makikita natin na ang merge sa ating branch ay nagdudulot ng mga pagkasalungat.
$ git merge mundo
Auto-merging hello.rb
CONFLICT (content): Merge conflict in hello.rb
Resolved 'hello.rb' using previous resolution.
Automatic merge failed; fix conflicts and then commit the result.
Gayunpaman kung tayo ay magpatakbo nito ng -Xours
o -Xtheirs
ito ay hindi.
$ git merge -Xours mundo
Auto-merging hello.rb
Merge made by the 'recursive' strategy.
hello.rb | 2 +-
test.sh | 2 ++
2 files changed, 3 insertions(+), 1 deletion(-)
create mode 100644 test.sh
Sa kasong iyon, sa halip na makakuha ka ng pagkasalungat na mga marka sa file sa “hello mundo” sa isang panig at ang “hola world” sa kabila, ito ay pipili sa “hola world”. Gayunpaman, lahat ng ibang hindi nagsasalungat na mga pagbabago sa branch na iyon ay magtagumpay na nai-merge.
Ang opsyon na ito ay maaari ding ipasa sa git merge-file
na utos na nakita namin kamakailan lang sa pamamagitan sa pagpatakbo ng isang bagay na tulad ng git merge-file --ours
para sa indibidwal na file na mga merge.
Kung nais mong gawin ang isang bagay na tulad nito pero walang Git at kahit na subukan upang i-merge ang mga pagbabago mula sa ibang panig, mayroong higit pa na draconian na opsyon, kung saan ay ang “ours” merge na diskarte. This is different from the “ours” recursive merge option.
Ito ay karaniwang gumawa ng pekeng merge. Ito ay nagtatala ng isang bagong commit na may parehong mga branch bilang magulang, ngunit hindi ito tumitingin sa branch na iyong pinag-merge. Ito lamang ay simpleng nagtatala bilang resulta sa merge na eksaktong code sa iyong kasalukuyang branch.
$ git merge -s ours mundo
Merge made by the 'ours' strategy.
$ git diff HEAD HEAD~
$
Maaari mong makita na doon na walang pagkakaiba sa pagitan ng branch na kami ay nandoon at ang resulta sa pag-merge.
Madalas itong maging kapaki-pakinabang sa karaniwang dayain ang Git sa pag-iisip na ang branch ay na-merge na kapag gagawa ka ng merge sa susunod.
Halimbawa, sabihin mo na branched off sa isang release
na branch at gumawa ng ilang trabaho nito na gusto mong i-merge pabalik sa iyong master
na branch sa isang punto.
Kasabay nito ang ilang bugfix sa master
kinakailangan na naka-backported sa iyong release
na branch.
Maaari mong i-merge ang bugfix na branch sa release
na branch at ang merge -s ours`din na parehong branch sa iyong `master
na branch (kahit na ang pag-aayos ay naroroon na) kaya kapag sa paglaon mo i-merge ang release
na branch muli, walang mga salungatan mula sa bugfix.
Subtree na Pag-merge
Ang ideya ng subtree na merge ay ikaw ay mayroong dalawang proyekto, at isa sa mga proyekto ay nagmamapa sa isang subdirektoryo ng isa pa. Kapag tinukoy mo ang isang subtree merge, ang git ay kadalasang sapat na matalino na malaman na ang isa ay isang subtree sa iba at merge na angkop.
Tayo ay tumingin ng malalim sa isang halimbawa sa pagdagdag ng hiwalay na proyekto sa isang umiiral na proyekto at pagkatapos ang pag-merge sa code sa pangalawa sa isang subdirektoryo ng una.
Una, tayo ay magdagdag ng Rack na aplikasyon sa ating proyekto. Idagdag natin ang Rack na proyekto bilang isang remote na reperensiya sa iyong sariling proyekto at pagkatapos tingnan ito sa sarili mong branch:
$ git remote add rack_remote https://github.com/rack/rack
$ git fetch rack_remote --no-tags
warning: no common commits
remote: Counting objects: 3184, done.
remote: Compressing objects: 100% (1465/1465), done.
remote: Total 3184 (delta 1952), reused 2770 (delta 1675)
Receiving objects: 100% (3184/3184), 677.42 KiB | 4 KiB/s, done.
Resolving deltas: 100% (1952/1952), done.
From https://github.com/rack/rack
* [new branch] build -> rack_remote/build
* [new branch] master -> rack_remote/master
* [new branch] rack-0.4 -> rack_remote/rack-0.4
* [new branch] rack-0.9 -> rack_remote/rack-0.9
$ git checkout -b rack_branch rack_remote/master
Branch rack_branch set up to track remote branch refs/remotes/rack_remote/master.
Switched to a new branch "rack_branch"
Ngayon meron na tayong root sa Rack na proyekti sa ating rack_branch
na branch at ating sariling proyekto sa master
na branch.
Kung ikaw ay magcheck out ng isa at pagkatapos sa iba, maaari mong makita na sila ay may ibang mga root na proyekto:
$ ls
AUTHORS KNOWN-ISSUES Rakefile contrib lib
COPYING README bin example test
$ git checkout master
Switched to branch "master"
$ ls
README
Ito ay uri ng isang kakaibang konsepto. Hindi lahat ng mga branch sa iyong repositoryo ay talagang may mga branch sa parehong proyekto. Ito ay hindi karaniwan, dahil ito ay bihirang kapaki-pakinabang, ngunit ito ay medyo madali na magkaroon ng mga branch na naglalaman ng ganap na kakaibang kasaysayan.
Sa kasong ito, gusto nating i-pull ang Rack na proyekto sa ating master
na proyekto bilang isang subdirektoryo.
Magagawa natin iyan sa Git na may git read-tree
.
Matutunan mo ang higit na tungkol sa read-tree
at ang mga kaibigan nito sa Mga Panloob ng GIT, ngunit para sa ngayon ay malaman ang root tree sa isang branch sa iyong kasalukuyang staging area at tinatrabahuang direktoryo.
Kakalipat lang natin pabalik sa iyong master
na branch, at nagpull tayo sa rack_branch
na branch sa rack
na subdirektoryo sa ating master
na branch sa ating pangunahing proyekto:
$ git read-tree --prefix=rack/ -u rack_branch
When we commit, it looks like we have all the Rack files under that subdirectory – as though we copied them in from a tarball. What gets interesting is that we can fairly easily merge changes from one of the branches to the other. So, if the Rack project updates, we can pull in upstream changes by switching to that branch and pulling:
$ git checkout rack_branch
$ git pull
Then, we can merge those changes back into our master
branch.
To pull in the changes and prepopulate the commit message, use the --squash
option, as well as the recursive merge strategy’s -Xsubtree
option.
(The recursive strategy is the default here, but we include it for clarity.)
$ git checkout master
$ git merge --squash -s recursive -Xsubtree=rack rack_branch
Squash commit -- not updating HEAD
Automatic merge went well; stopped before committing as requested
All the changes from the Rack project are merged in and ready to be committed locally.
You can also do the opposite – make changes in the rack
subdirectory of your master branch and then merge them into your rack_branch
branch later to submit them to the maintainers or push them upstream.
This gives us a way to have a workflow somewhat similar to the submodule workflow without using submodules (which we will cover in Mga Submodule). We can keep branches with other related projects in our repository and subtree merge them into our project occasionally. It is nice in some ways, for example all the code is committed to a single place. However, it has other drawbacks in that it’s a bit more complex and easier to make mistakes in reintegrating changes or accidentally pushing a branch into an unrelated repository.
Another slightly weird thing is that to get a diff between what you have in your rack
subdirectory and the code in your rack_branch
branch – to see if you need to merge them – you can’t use the normal diff
command.
Instead, you must run git diff-tree
with the branch you want to compare to:
$ git diff-tree -p rack_branch
Or, to compare what is in your rack
subdirectory with what the master
branch on the server was the last time you fetched, you can run
$ git diff-tree -p rack_remote/master