Git
Chapters ▾ 2nd Edition

9.1 Ang Git at iba pang mga Sistema - Git bilang isang Kliyente

Ang mundo ay hindi perpekto. Kadalasan, hindi ka madaling makapagpalit ng bawat proyekto na nakikipag-ugnayan sa iyo sa Git. Minsan ikaw ay mananatili sa isang proyekto gamit ang ibang VCS, at gugustuhing ito ay Git. Papalipasin natin ang unang bahagi ng kabanatang ito sa pag-aaral tungkol sa mga paraan sa paggamit ng Git bilang isang kliyente kapag ang iyong tinatrabaho ay naka-host sa isang ibang sistema.

Sa ilang punto, maaaring gugustuhin mong palitan ang iyong umiiral na proyekto sa Git. Ang pangalawang bahagi ng kabanatang ito ay sumasakop sa kung papaano ilipat ang iyong proyekto sa Git mula sa iilang nakatukoy na mga sistema, pati na rin ang isang pamamaraan na gagana kung walang umiiral na pre-built na import na kasangkapan.

Git bilang isang Kliyente

Ang Git ay nagbibigay kay ganda-gandang karanasan para sa mga developer na nalaman na ng maraming tao kung papaano gamitin ito sa kanilang istasyon ng pagtatrabaho, kahit kung ang natitira sa kanilang koponan ay gumagamit ng isang buong kakaibang VCS. May maraming mga adapter na ito, na tinatawag na “mga tulay,” na maaaring magamit. Dito ay sasakupin natin ang mga bagay na maaaring mong makasalubong sa kagubatan.

Git at Subversion

Isang malaking bahagi ng mga proyekto ng open source na development at isang magandang numero ng korporasyon na mga proyekto ay gumagamit ng Subversion upang mamahala ng kanilang source code. Ito ay nasa paligid na sa higit na isang dekada, at para sa madalas na pagkakataon ito ay ang de facto na VCS na pagpipilian para sa mga open-source na proyekto. Ito rin ay sobrang katulad sa maraming paraan sa CVS, na itinuring na malaking lalaki ng mundo ng source-control bago sa iyon.

Isa sa dakilang mga tampok ng Git ay isang dalawang-direksyong tulay sa Subversion na tinatawag na git svn. Ito ay isang kasangkapan na nagpapahintulot sa iyo na gumamit ng Git bilang isang balidong kliyente sa isang Subversion na server, kaya maaari mong gamitin ang lahat ng mga lokal na tampok ng Git at pagkatapos ay i-push sa isang Subversion na server na kunyari ikaw ay lokal na gumagamit ng Subversion. Ito ay nangangahulugang maaari kang gumawa ng lokal na pag-branch at pag-merge, gumamit ng staging na lawak, gumamit ng pag-rebase at pag-cherry-pick, at iba pa, habang ang iyong mga katulong ay patuloy na nagtatrabaho sa kanilang madilim at makalumang pamamaraan. Magandang paraan na ilabas nang panakaw ang Git sa korporasyon na environment at tumulong sa iyong kapwa mga developer na maging mas mahusay habang ikaw ay naka-lobby upang kunin ang imprastrakturang nabago upang ganap na suportahan ang Git. Ang Subversion na tulay ay ang pasukan na droga sa DVCS na mundo.

git svn

Ang base na utos sa Git para sa lahat ng Subversion na pagtutulay na mga utos ay ang git svn. Ito ay kumukuha ng ilang mga utos, kaya ipapakita natin ang madalas na karaniwan habang pumupunta sa iilang simpleng workflow.

Importanteng tandaan na kapag ikaw ay gumagamit ng git svn, ikaw ay nakikipag-ugnayan sa Subversion, na isang sistema na sobrang kakaibang gumagana mula sa Git. Bagaman maaari kang gumawa ng lokal na pag-branch at pag-merge, ito ay pangkalahatang pinakamahusay upang panatilihin ang iyong kasaysayan bilang linear hangga’t maaari sa pamamagitan ng pag-rebase ng iyong trabaho, at iiwasan ang paggawa ng mga bagay katulad ng sabay-sabay na pakikipag-ugnayan sa isang Git na remote na repositoryo.

Huwag muling isulat ang iyong kasaysayan at subukang mag-push muli, at huwag mag-push sa isang kahilera na Git na repositoryo upang makipagtulungan kasama ang kapwa mga developer ng Git sa parehong pagkakataon. Ang Subversion ay maaaring magkaroon lamang ng isang linear na kasaysayan, at madali itong ikalito. Kung ikaw ay nagtatrabaho sa isang koponan, at ang ilan ay gumagamit ng SVN at ang iba ay gumagamit ng Git, siguraduhing ang lahat ay gumagamit ng SVN na server upang makipagtulungan – ang paggawa nito ay gagawing mas madali ang iyong buhay.

Pag-set Up

Upang ipakita ang functionality na ito, kailangan mo ng isang tipikal na SVN na repositoryo na kung saan mayroon kang access sa pagsulat. Kung gusto mong kopyahin ang mga halimbawang ito, kailangan mong gumawa ng isang nasusulatang kopya ng isang SVN na test na repositoryo. Upang madaling gawin ito, maaari mong gamitin ang isang kasangkapan na tinatawag na svnsync na dumarating kasama ang Subversion.

Upang sumunod, una mong kailangang gumawa ng isang bagong lokal na Subversion na repositoryo.

$ mkdir /tmp/test-svn
$ svnadmin create /tmp/test-svn

Pagkatapos, paganahin lahat ang mga user upang baguhin ang mga revprop – ang madaling paraan ay ang pagdagdag ng isang pre-revprop-change na iskrip na palaging naglalabas ng 0:

$ cat /tmp/test-svn/hooks/pre-revprop-change
#!/bin/sh
exit 0;
$ chmod +x /tmp/test-svn/hooks/pre-revprop-change

Maaari mo na ngayong i-sync ang proyektong ito sa iyong lokal na makina sa pamamagitan ng pagtawag ng svnsync init gamit ang patungo at mula na mga repositoryo.

$ svnsync init file:///tmp/test-svn \
  http://your-svn-server.example.org/svn/

Itinatakda nito ang mga katangian upang patakbuhin ang sync. Maaari mo na ring i-clone ang code sa pamamagitan ng pagpapatakbo ng

$ svnsync sync file:///tmp/test-svn
Committed revision 1.
Copied properties for revision 1.
Transmitting file data .............................[...]
Committed revision 2.
Copied properties for revision 2.
[…]

Bagaman ang operasyong ito ay tumatagal lamang ng ilang mga minuto, kung susubukan mong kopyahin ang orihinal na mga repositoryo sa ibang remote na repositoryo sa halip ng isang lokal, ang proseso ay tatagal ng halos isang oras, kahit bagaman mayroong mas mababa kaysa sa 100 na mga commit. Ang Subversion ay kailangang mag-clone ng isang rebisyon sa isang pagkakataon at pagkatapos ay i-push ito pabalik sa ibang repositoryo – ito ay nakakatawang hindi mabisa, ngunit ito lamang ang madaling paraan upang gawin ito.

Pagsisimula

Ngayon na mayroon ka nang isang Subversion na repositoryo kung saan ikaw ay may access sa pagsulat, maaari ka nang tumahak sa isang tipikal na workflow. Magsisimula ka sa git svn clone na utos, na nag-i-import ng isang buong Subversion na repositoryo sa isang lokal na Git na repositoryo. Tandaan na kung ikaw ay nag-i-import mula sa isang tunay na naka-host na Subversion na repositoryo, dapat mong palitan ang file:///tmp/test-svn dito gamit ang URL ng iyong Subversion na repositoryo:

$ git svn clone file:///tmp/test-svn -T trunk -b branches -t tags
Initialized empty Git repository in /private/tmp/progit/test-svn/.git/
r1 = dcbfb5891860124cc2e8cc616cded42624897125 (refs/remotes/origin/trunk)
    A	m4/acx_pthread.m4
    A	m4/stl_hash.m4
    A	java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
    A	java/src/test/java/com/google/protobuf/WireFormatTest.java
…
r75 = 556a3e1e7ad1fde0a32823fc7e4d046bcfd86dae (refs/remotes/origin/trunk)
Found possible branch point: file:///tmp/test-svn/trunk => file:///tmp/test-svn/branches/my-calc-branch, 75
Found branch parent: (refs/remotes/origin/my-calc-branch) 556a3e1e7ad1fde0a32823fc7e4d046bcfd86dae
Following parent with do_switch
Successfully followed parent
r76 = 0fb585761df569eaecd8146c71e58d70147460a2 (refs/remotes/origin/my-calc-branch)
Checked out HEAD:
  file:///tmp/test-svn/trunk r75

Ito ay nagpapatakbo ng katumbas na dalawang mga utos – ang git svn init na sinusundan ng git svn fetch – sa URL na iyong ibinigay. Ito ay maaaring magtagal ng ilang saglit. Kung, halimbawa, ang pagsubok na proyekto ay mayroon lamang halos 75 na mga commit at ang codebaase ay hindi ganon kalaki, ang Git gayunpaman ay dapat mag-check out sa bawat bersyon, iisa sa bawat pagkakataon, at mag-commit nito nang indibidwal. Para sa isang proyekto na may daan-daan o libo-libong mga commit, ito ay maaaring literal na tatagal ng ilang mga oras o kahit mga araw upang matapos.

Ang -T trunk -b branches -t tags na parte ay sasabihan ang Git na itong Subversion na repositoryo ay sumusunod sa batayan ng pag-branch at pag-tag na mga kombensyon. Kung kakaiba mong papangalanan ang iyong trunk, mga branch, o mga tag, maaari mong baguhin ang mga opsyon na ito. Dahil ito ay sobrang karaniwan, maaari mong palitan ang buong parte gamit ang -s, na nangangahulugang pamantayan na layout at nagpapahiwatig ng lahat ng mga opsyon na iyon. Ang sumusunod na uto ay katumbas:

$ git svn clone file:///tmp/test-svn -s

Sa puntong ito, dapat kang magkaroon ng isang balidong Git na repositoryo na nag-import ng iyong mga branch at mga tag:

$ git branch -a
* master
  remotes/origin/my-calc-branch
  remotes/origin/tags/2.0.2
  remotes/origin/tags/release-2.0.1
  remotes/origin/tags/release-2.0.2
  remotes/origin/tags/release-2.0.2rc1
  remotes/origin/trunk

Tandaan kung paano namamahala ang kasangkapang ito sa Subversion na mga tag bilang remote na mga ref. Tingnan natin ng malapitan gamit ang Git plumbing na utos na show-ref:

$ git show-ref
556a3e1e7ad1fde0a32823fc7e4d046bcfd86dae refs/heads/master
0fb585761df569eaecd8146c71e58d70147460a2 refs/remotes/origin/my-calc-branch
bfd2d79303166789fc73af4046651a4b35c12f0b refs/remotes/origin/tags/2.0.2
285c2b2e36e467dd4d91c8e3c0c0e1750b3fe8ca refs/remotes/origin/tags/release-2.0.1
cbda99cb45d9abcb9793db1d4f70ae562a969f1e refs/remotes/origin/tags/release-2.0.2
a9f074aa89e826d6f9d30808ce5ae3ffe711feda refs/remotes/origin/tags/release-2.0.2rc1
556a3e1e7ad1fde0a32823fc7e4d046bcfd86dae refs/remotes/origin/trunk

Hindi ito gagawin ng Git kapag ito ay nagko-clone mula sa isang Git na server; narito ang kung ano ang hitsura ng repositoryo na may mga tag pagkatapos ng isang preskong clone:

$ git show-ref
c3dcbe8488c6240392e8a5d7553bbffcb0f94ef0 refs/remotes/origin/master
32ef1d1c7cc8c603ab78416262cc421b80a8c2df refs/remotes/origin/branch-1
75f703a3580a9b81ead89fe1138e6da858c5ba18 refs/remotes/origin/branch-2
23f8588dde934e8f33c263c6d8359b2ae095f863 refs/tags/v0.1.0
7064938bd5e7ef47bfd79a685a62c1e2649e2ce7 refs/tags/v0.2.0
6dcb09b5b57875f334f61aebed695e2e4193db5e refs/tags/v1.0.0

Ang Git ay direktang magpi-fetch ng mga tag sa refs/tags, sa halip ng pagtrato sa kanila bilang remote na mga branch.

Pag-commit Pabalik sa Subversion

Ngayon na mayroon ka nang isang gumaganang direktoryo, maaari ka nang gumawa ng ilang trabaho at i-push ang iyong mga commit pabalik sa upstream, ang epektibong paggamit ng Git bilang isang SVN na kliyente. Kung ikaw ay nag-edit ng isa sa mga file at nag-commit nito, mayroon kang isang commit na lokal na umiiral sa Git na hindi umiiral sa Subversion na server:

$ git commit -am 'Adding git-svn instructions to the README'
[master 4af61fd] Adding git-svn instructions to the README
 1 file changed, 5 insertions(+)

Susunod, kailangan mong i-push ang iyong pagbabago sa upstream. Pansinin kung paano nito binabago ang paraan ng iyong pagtatrabaho sa Subversion – maaari kang gumawa ng iilang mga commit habang naka-offline at pagkatapos ay i-push lahat ang mga ito nang sabay-sabay sa Subversion na server. Upang mag-push sa isang Subversion na server, patakbuhin mo ang git svn dcommit na utos:

$ git svn dcommit
Committing to file:///tmp/test-svn/trunk ...
    M	README.txt
Committed r77
    M	README.txt
r77 = 95e0222ba6399739834380eb10afcd73e0670bc5 (refs/remotes/origin/trunk)
No changes between 4af61fd05045e07598c553167e0f31c84fd6ffe1 and refs/remotes/origin/trunk
Resetting to the latest refs/remotes/origin/trunk

Kinukuha nito lahat ng mga commit na ginawa mo sa itaas ng Subversion na server na code, gagawa ng isang Subversion na commit sa bawat isa, at pagkatapos ay susulatang muli ang iyong lokal na Git na commit upang magsama ng isang natatanging identifier. Ito ay importante dahil ito ay nangangahulugan na ang lahat ng SHA-1 na mga checksum para sa iyong mga commit na pagbabago. Bahagyang para sa dahilang ito, ang pagtatrabaho sa Git na nakabase na remote na mga bersyon ng iyong mga proyekto kasabay nito ang isang Subversion na server ay hindi isang magandang ideya. Kung titingnan mo ang huling commit, maaari mong tingnan ang bagong git-svn-id na naidagdag:

$ git log -1
commit 95e0222ba6399739834380eb10afcd73e0670bc5
Author: ben <ben@0b684db3-b064-4277-89d1-21af03df0a68>
Date:   Thu Jul 24 03:08:36 2014 +0000

    Adding git-svn instructions to the README

    git-svn-id: file:///tmp/test-svn/trunk@77 0b684db3-b064-4277-89d1-21af03df0a68

Pansinin na ang SHA-1 na checksum na orihinal na nagsimula sa 4af61fd kapag ang iyong na-commit ngayon ay nagsisimula sa 95e0222. Kung gusto mong mag-push sa kapwa isang Git na server at isang Subversion na server, kailangan mo munang mag-push (dcommit) sa Subversion na server, dahil ang aksyong iyon ay bumubago sa iyong commit na datos.

Pag-pull papasok sa Bagong mga Pagbabago

Kung ikaw ay nagtatrabaho kasama ang ibang mga developer, pagkatapos sa ilang punto isa sa inyo ay mag-push, at ang isa pa ay susubukang mag-push ng isang pagbabago na magkasalungat. Ang pagbabagong iyon ay hindi tatanggapin hanggang magmi-merge ka sa kanilang trabaho. Sa git svn, ito ay magmumukhang ganito:

$ git svn dcommit
Committing to file:///tmp/test-svn/trunk ...

ERROR from SVN:
Transaction is out of date: File '/trunk/README.txt' is out of date
W: d5837c4b461b7c0e018b49d12398769d2bfc240a and refs/remotes/origin/trunk differ, using rebase:
:100644 100644 f414c433af0fd6734428cf9d2a9fd8ba00ada145 c80b6127dd04f5fcda218730ddf3a2da4eb39138 M	README.txt
Current branch master is up to date.
ERROR: Not all changes have been committed into SVN, however the committed
ones (if any) seem to be successfully integrated into the working tree.
Please see the above messages for details.

Upang malutas ang sitwasyong ito, maaari mong patakbuhin ang git svn rebase, na magpu-pull ng anumang mga pagbabago sa server na hindi pa nasa iyo at iri-rebase ang anumang trabaho na nasa iyo sa itaas ng anumang nasa server:

$ git svn rebase
Committing to file:///tmp/test-svn/trunk ...

ERROR from SVN:
Transaction is out of date: File '/trunk/README.txt' is out of date
W: eaa029d99f87c5c822c5c29039d19111ff32ef46 and refs/remotes/origin/trunk differ, using rebase:
:100644 100644 65536c6e30d263495c17d781962cfff12422693a b34372b25ccf4945fe5658fa381b075045e7702a M	README.txt
First, rewinding head to replay your work on top of it...
Applying: update foo
Using index info to reconstruct a base tree...
M	README.txt
Falling back to patching base and 3-way merge...
Auto-merging README.txt
ERROR: Not all changes have been committed into SVN, however the committed
ones (if any) seem to be successfully integrated into the working tree.
Please see the above messages for details.

Ngayon, lahat ng iyong trabaho ay nasa itaas ng kung ano ang nasa Subversion na server, kaya maaari kang matagumpay na mag-dcommit:

$ git svn dcommit
Committing to file:///tmp/test-svn/trunk ...
    M	README.txt
Committed r85
    M	README.txt
r85 = 9c29704cc0bbbed7bd58160cfb66cb9191835cd8 (refs/remotes/origin/trunk)
No changes between 5762f56732a958d6cfda681b661d2a239cc53ef5 and refs/remotes/origin/trunk
Resetting to the latest refs/remotes/origin/trunk

Tandaan na hindi tulad ng Git, na nangangailangan sa iyo na mag-merge sa upstream na trabaho na hindi pa nasa iyo sa lokal bago ka maka-push, ang git svn ay ipapagawa lamang ito sa iyo kung ang mga pagbabago ay magkasalungat (masyadong katulad ng kung paano gumagana ang Subversion). Kung may ibang tao na nagpu-push ng pagbabago sa isang file at pagkatapos ay nag-push ka ng isang pagbabago sa ibang file, ang iyong dcommit ay gagana ng maayos.

$ git svn dcommit
Committing to file:///tmp/test-svn/trunk ...
    M	configure.ac
Committed r87
    M	autogen.sh
r86 = d8450bab8a77228a644b7dc0e95977ffc61adff7 (refs/remotes/origin/trunk)
    M	configure.ac
r87 = f3653ea40cb4e26b6281cec102e35dcba1fe17c4 (refs/remotes/origin/trunk)
W: a0253d06732169107aa020390d9fefd2b1d92806 and refs/remotes/origin/trunk differ, using rebase:
:100755 100755 efa5a59965fbbb5b2b0a12890f1b351bb5493c18 e757b59a9439312d80d5d43bb65d4a7d0389ed6d M	autogen.sh
First, rewinding head to replay your work on top of it...

Ito ay importanteng tandaan, dahil ang kinalalabasan ay isang estado ng proyekto na hindi umiiral sa alinman sa iyong mga kompyuter kapag ikaw ay nag-push. Kung ang mga pagbabago ay hindi tugma ngunit walang magkasalungat, maaari mong makuha ang mga isyu na mahirap na suriin. Ito ay magkaiba kaysa sa paggamit ng isang Git na server – sa Git, maaari mong ganap na subukan ang estado sa iyong kliyente na sistema bago i-ambag ito, samantalang sa SVN, hindi mo kailanmang madaling matiyak na ang mga estado bago sa commit at pagkatapos sa commit ay magkakahawig.

Kailangan mo ring patakbuhin ang utos na ito upang i-pull papasok ang mga pagbabago mula sa Subversion na server, kahit na kung ikaw ay hindi pa handang sariling mag-commit. Maaari mong patakbuhin ang git svn fetch upang kunin ang bagong datos, ngunit ang git svn rebase ay gagawa sa fetch at pagkatapos ay ia-update ang iyong lokal na mga commit.

$ git svn rebase
    M	autogen.sh
r88 = c9c5f83c64bd755368784b444bc7a0216cc1e17b (refs/remotes/origin/trunk)
First, rewinding head to replay your work on top of it...
Fast-forwarded master to refs/remotes/origin/trunk.

Ang pagpapatakbo ng git svn rebase sa bawat pagkakataon ay sinisiguradong ang iyong code ay palaging napapanahon. Kailangan mong siguraduhin na ang iyong tinatrabahong direktoryo ay malinis kapag ikaw ay nagpatakbo nito, bagaman. Kung mayroon kang lokal na mga pagbabago, kailangan mong alinmang i-stash ang iyong trabaho o pansamantalang i-commit ito bago patakbuhin git svn rebase – kung hindi man, ang utos ay hihinto kung nakikita nito na ang rebase ay magreresulta ng isang merge na salungatan.

Mga Isyu sa Pag-branch ng Git

Kapag ikaw ay naging komportable na sa isang Git workflow, malamang ikaw ay makakalikha ng paksa na mga branch, gumawa ng trabaho sa mga ito, at pagkatapos ay papasok na i-merge ang mga ito. Kung ikaw ay nag-push sa isang Subversion na server sa pamamagitan ng git svn, malamang gusto mong i-rebase ang iyong trabaho sa isang solong branch sa bawat oras sa halip na sama-samang i-merge ang mga branch. Ang dahilan upang gustuhin ang pag-rebase ay ang Subversion ay may isang linear na kasaysayan at hindi nakikitungo katulad ng Git, kaya ang git svn ay sumusunod lamang sa unang magulang kapag pinapalitan ang mga snapshot sa Subversion na mga commit.

Ipagpalagay na ang iyong kasaysayan ay magmumukhang katulad ng sumusunod: lumikha ka ng isang experiment na branch, gumawa ng dalawang mga commit, at pagkatapos ay na-merge ang mga ito pabalik sa master. Kapag ikaw ay nag-dcommit, makikita mo ang awtput na katulad nito:

$ git svn dcommit
Committing to file:///tmp/test-svn/trunk ...
    M	CHANGES.txt
Committed r89
    M	CHANGES.txt
r89 = 89d492c884ea7c834353563d5d913c6adf933981 (refs/remotes/origin/trunk)
    M	COPYING.txt
    M	INSTALL.txt
Committed r90
    M	INSTALL.txt
    M	COPYING.txt
r90 = cb522197870e61467473391799148f6721bcf9a0 (refs/remotes/origin/trunk)
No changes between 71af502c214ba13123992338569f4669877f55fd and refs/remotes/origin/trunk
Resetting to the latest refs/remotes/origin/trunk

Ang pagpapatakbo ng dcommit sa isang branch na may na-merge na kasaysayan ay gagana ng maayos, maliban kapag ikaw ay tumingin sa iyong kasaysayan ng Git na proyekto, hindi nito sinulatang muli ang alinman sa mga commit na ginawa mo sa experiment na branch – sa halip, ang lahat ng mga pagbabagong iyon ay magpapakita sa SVN na bersyon ng solong merge na commit.

Kapag may ibang tao na magko-clone ng trabahong iyon, lahat ng makikita nila ay ang merge na commit kasama ang lahat na trabahong naisiksik sa iyon, kagaya ng pagpatakbo mo ng git merge --squash; hindi nila makikita ang commit na datos tungkol sa kung saan ito nanggaling o kailan ito na-commit.

Subversion na Pag-branch

Ang pag-branch sa Subversion ay hindi pareho sa pag-branch sa Git; kung maaari mong maiwasan ang paggamit nito nang masyado, iyon na marahil ang pinakamahusay. Gayunpaman, maaari kang bumuo at mag-commit sa mga branch sa Subversion gamit ang git svn.

Paglikha ng isang Bagong SVN na Branch

Upang lumikha ng isang panibagong branch sa Subversion, patakbuhin mo ang git svn branch [new-branch]:

$ git svn branch opera
Copying file:///tmp/test-svn/trunk at r90 to file:///tmp/test-svn/branches/opera...
Found possible branch point: file:///tmp/test-svn/trunk => file:///tmp/test-svn/branches/opera, 90
Found branch parent: (refs/remotes/origin/opera) cb522197870e61467473391799148f6721bcf9a0
Following parent with do_switch
Successfully followed parent
r91 = f1b64a3855d3c8dd84ee0ef10fa89d27f1584302 (refs/remotes/origin/opera)

Ginagawa nito ang katumbas ng svn copy trunk branches/opera na utos sa Subversion at tumatakbo sa Subversion na server. Importanteng tandaan na ito ay hindi nagchi-check out sa iyo sa branch na iyon; kung ikaw ay nag-commit sa puntong ito, ang commit na iyon ay pupunta sa trunk sa server, hindi sa opera.

Pagpapalit sa Aktibong mga Branch

Inaalam ng Git kung anong branch pupunta ang iyong mga dcommit sa pamamagitan ng paghahanap ng dulo ng anuman sa iyong Subversion na mga branch sa iyong kasaysayan – dapat kang magkaroon ng isa lamang, at ito dapat ang huli na may isang git-svn-id sa iyong kasalukuyang kasaysayan ng branch.

Kung gusto mong magtrabaho sa higit pa sa isang branch nang sabay-sabay, maaari kang magtakda ng lokal na mga branch sa dcommit sa isang tiyak na Subversion na mga branch sa pamamagitan ng pagsisimula sa kanila sa na-import na Subversion na commit para sa branch na iyon. Kung gusto mo ng isang opera na branch na maaari mong trabahuin na magkahiwalay, maaari mong patakbuhin ang

$ git branch opera remotes/origin/opera

Ngayon, kung gusto mong i-merge ang iyong opera na branch sa trunk (iyong master na branch), maaari mong gawin ito gamit ang isang normal na git merge. Ngunit kailangan mong magbigay ng isang deskriptibong commit na mensahe (gamit ang -m), o ang merge ay magsasabing “Merge branch opera” sa halip ng isang bagay na kapaki-pakinabang.

Tandaan na kahit ikaw ay gumagamit ng git merge upang gumawa ng operasyong ito, at ang merge malamang ay higit na mas madali kaysa sa Subversion (dahil ang Git ay awtomatikong tutuklas ng angkop na merge na base para sa iyo), ito ay hindi isang normal na Git merge na commit. Kailangan mong i-push ang datos pabalik sa isang Subversion na server na hindi nangangasiwa ng isang commit na sumusubaybay ng higit pa sa isang magulang; kaya, pagkatapos mong i-push pataas ito, magmumukha itong isang solong commit na nagsasanib ng lahat ng trabaho ng ibang branch sa ilalim ng isang solong commit. Pagkatapos mong i-merge ang isang branch patungo sa iba, hindi ka madaling makakabalik at magpatuloy sa pagtatrabaho sa branch na iyon, na normal mong nagagawa sa Git. Ang dcommit na utos na iyong pinatakbo ay nagbubura ng anumang impormasyon na nagsasabi kung anong branch ang papasok na na-merge, kaya ang kasunod na mga pag-kalkula ng merge-base ay magiging mali – ang dcommit ay ginagawa iyong git merge na resulta na magmukhang iyong pinatakbo ang git merge --squash. Sa kasamaang palad, walang magandang paraan upang maiwasan ang sitwasyong ito – ang Subversion ay hindi kayang mag-imbak ng impormasyong ito, kaya palagi kang nalulumpo sa mga limitasyon nito habang ikaw ay gumagamit nito bilang iyong server. Upang maiwasan ang mga isyu, kailangan mong burahin ang lokal na branch (sa kasong ito, opera) pagkatapos mong i-merge ito sa iyong trunk.

Subversion na mga Utos

Ang git svn na hanay ng kasangkapan ay nagbibigay ng iilang mga utos upang tulungang padaliin ang transisyon sa Git sa pamamagitan ng pagbibigay ng ilang functionality na katulad sa kung ano ang mayroon ka sa Subversion. Narito ang kaunting mga utos na nagbibigay sa iyo kung ano ang Subversion dati.

Kasaysayan ng Estilo ng SVN

Kung ikaw ay sanay na sa Subversion at gusto mong makita ang iyong kasaysayan sa SVN na output na estilo, maaari mong patakbuhin ang git svn log upang tingnan ang kasaysayan ng iyong commit sa SVN na pagka-format:

$ git svn log
------------------------------------------------------------------------
r87 | schacon | 2014-05-02 16:07:37 -0700 (Sat, 02 May 2014) | 2 lines

autogen change

------------------------------------------------------------------------
r86 | schacon | 2014-05-02 16:00:21 -0700 (Sat, 02 May 2014) | 2 lines

Merge branch 'experiment'

------------------------------------------------------------------------
r85 | schacon | 2014-05-02 16:00:09 -0700 (Sat, 02 May 2014) | 2 lines

updated the changelog

Kailangan mong malaman ang dalawang importanteng mga bagay tungkol sa git svn log. Una, ito ay gumagana habang offline, hindi tulad ng tunay na svn log na utos, na nagtatanong sa Subversion na server para sa datos. Pangalawa, ito ay nagpapakita lamang sa iyo ng mga commit na na-commit paitaas sa Subversion na server. Ang lokal na Git na mga commit na hindi mo na-dcommit ay hindi magpapakita; ni mga commit na ginawa ng mga tao sa Subversion na server sa pansamantala. Ito ay mas katulad ng huling kilalang estado ng mga commit sa Subversion na server.

SVN na Anotasyon

Masyadong katulad ng git svn log na utos na ginagaya ang svn log na utos habang offline, maaari kang makakuha ng katumbas ng svn annotate sa pagpapatakbo ng git svn blame [FILE]. Ang output ay magmumukhang katulad nito:

$ git svn blame README.txt
 2   temporal Protocol Buffers - Google's data interchange format
 2   temporal Copyright 2008 Google Inc.
 2   temporal http://code.google.com/apis/protocolbuffers/
 2   temporal
22   temporal C++ Installation - Unix
22   temporal =======================
 2   temporal
79    schacon Committing in git-svn.
78    schacon
 2   temporal To build and install the C++ Protocol Buffer runtime and the Protocol
 2   temporal Buffer compiler (protoc) execute the following:
 2   temporal

Muli, ito ay hindi nagpapakita ng mga commit na lokal mong ginawa sa Git o na-push sa Subversion sa pansamantala.

SVN Server na Impormasyon

Maaari ka ring kumuha ng parehong pagkakaayos ng impormasyon na svn info na ibinibigay sa iyo sa pamamagitan ng pagpapatakbo ng git svn info:

$ git svn info
Path: .
URL: https://schacon-test.googlecode.com/svn/trunk
Repository Root: https://schacon-test.googlecode.com/svn
Repository UUID: 4c93b258-373f-11de-be05-5f7a86268029
Revision: 87
Node Kind: directory
Schedule: normal
Last Changed Author: schacon
Last Changed Rev: 87
Last Changed Date: 2009-05-02 16:07:37 -0700 (Sat, 02 May 2009)

Ito ay katulad ng blame at log na tumatakbo habang offline at napapanahon lamang batay sa huling panahon nung ikaw ay nakipag-ugnayan sa Subversion na server.

Hindi Pagpapansin sa Kung Ano Ang Hindi Pinapansin ng Subversion

Kung ikaw ay nag-clone ng isang Subversion na repositoryo na may svn:ignore na mga katangian na naitakda kahit saan, malamang gusto mong magtakda ng nararapat na .gitignore na mga file upang hindi ka aksidenteng maka-commit ng mga file na hindi dapat i-commit. Ang git svn ay may dalawang mga utos upang tumulog sa isyung ito. Ang una ay ang git svn create-ignore, na awtomatikong gumagawa ng nararapat na .gitignore na mga file para sa iyo upang ang iyong susunod na commit ay maglalaman ng mga ito.

Ang pangalawang utos ay git svn show-ignore, na nagpi-print sa stdout ng mga linya na kailangan mong lagyan ng isang .gitignore na file upang ipasa ang output sa iyong project exclude na file:

$ git svn show-ignore > .git/info/exclude

Sa paraang iyon, hindi mo kakalatan ang proyekto ng .gitignore na mga file. Ito ay isang magandang opsyon kung ikaw lamang ang gumagamit ng Git sa isang Subversion na koponan, at iyong mga kasama sa koponan ay hindi gustong gumamit ng .gitignore na mga file sa proyekto.

Git-Svn na Buod

Ang git svn na mga kasangkapan ay kapaki-pakinabang kung ikaw ay nananatili sa isang Subversion na server, o kaya ay nasa isang development na environment na nangangailangan ng pagpapatakbo ng isang Subversion na server. Dapat mong isaalang-alang na ito ay sumalanta sa Git, gayunpaman, o makakasalubong ka ng mga isyu sa pagsasalin na maaaring lumito sa iyo at iyong mga katulong. Upang makaiwas sa gulo, subukang sundin ang mga patnubay na ito:

  • Magpanatili ng isang linear na kasaysayan ng Git na hindi naglalaman ng merge na mga commit na ginawa sa pamamagitan ng git merge. I-rebase ang anumang trabaho na ginawa mo sa labas ng iyong mainline na branch pabalik nito; huwag itong i-merge nang papasok.

  • Huwag mag-set up at magkipagtulunga sa isang hiwalay na Git server. Posibleng magkaroon ng isa upang pabilisin ang mga clone para sa bagong mga developer, ngunit huwag mag-push ng kahit ano sa ito na walang isang git-svn-id na entry. Marahil gugustuhin mo ring magdagdag ng isang pre-receive hook na sumusuri sa bawat commit na mensahe para sa isang git-svn-id at tatanggihan ang mga push na naglalaman ng mga commit na wala nito.

Kung susundin mo ang mga patnubay na iyon, ang pagtatrabaho gamit ang isang Subversion server ay maaaring maging mas mapagtitiisan. Gayunpaman, kung ito ay posibleng ilipat sa isang tunay na Git server, ang paggawa nito ay maaaring higit pang maging pakinabang sa iyong koponan.

Git at Mercurial

Ang DVCS na sansinukob ay mas malaki kaysa sa Git lamang. Sa katunayan, mayroong maraming ibang mga sistema sa espasyong ito, bawat isa ay may kani-kanilang sariling anggulo sa kung papaano tamang gumawa ng pagpamahagi ng version control. Bukod sa Git, ang pinakapopular ay ang Mercurial, at ang dalawa ay sobrang katulad sa maraming mga kaparaanan.

Ang magandang balita, kung mas gusto mo ang kaugalian sa panig ng kliyente ng Git ngunit nagtatrabaho sa isang proyekto na ang source code ay kontrolado gamit ang Mercurial, may isang paraan upang gumamit ng Git bilang isang kliyente para sa isang Mercurial na naka-host na repositoryo. Dahil ang paraan ng pakikipag-usap ng Git sa server na mga repositoryo ay sa pamamagitan ng mga remote, ito ay darating na hindi sorpresa na ang tulay na ito ay naipatupad bilang isang remote na katulong. Ang pangalan ng proyekto ay git-remote-hg, at ito ay maaaring matagpuan sa https://github.com/felipec/git-remote-hg.

git-remote-hg

Una, kailangan mong mag-install ng git-remote-hg. Ito ay talagang nagtatadhana sa pagpapahulog sa file nito saanman sa iyong landas, katulad nito:

$ curl -o ~/bin/git-remote-hg \
  https://raw.githubusercontent.com/felipec/git-remote-hg/master/git-remote-hg
$ chmod +x ~/bin/git-remote-hg

…ipagpalagay na ang ~/bin ay nasa iyong $PATH. Ang git-remote-hg ay may iba pang dependensya: ang mercurial na library para sa Python. Kung ikaw ay mayroon nang Python na naka-install, ito ay kasing simple ng:

$ pip install mercurial

(Kung wala ka pang Python na naka-install, bisitahin ang https://www.python.org/ at unang kunin ito.)

Ang huling bagay na kakailanganin mo ay ang Mercurial na kliyente. Pumunta sa https://www.mercurial-scm.org/ at i-install ito kung hindi mo pa nagawa.

Ngayon handa ka nang gumiwang. Lahat ng kailangan mo ay isang Mercurial na repositoryo kung saan ka magpu-push. Sa kabutihang palad, ang bawat Mercurial na repositoryo ay maaaring kumilos sa ganitong paraan, kaya gagamitin lang nating ang "hello world" na repositoryo na ginagamit ng lahat upang matuto ng Mercurial:

$ hg clone http://selenic.com/repo/hello /tmp/hello

Pagsisimula

Ngayon na mayroon na tayong isang angkop na “server-side” na repositoryo, maaari tayong tumahak sa isang tipikal na workflow. Batay sa iyong makikita, ang dalawang mga sistemang ito ay sapat na magkatulad nang walang masyadong alitan.

As always with Git, first we clone:

$ git clone hg::/tmp/hello /tmp/hello-git
$ cd /tmp/hello-git
$ git log --oneline --graph --decorate
* ac7955c (HEAD, origin/master, origin/branches/default, origin/HEAD, refs/hg/origin/branches/default, refs/hg/origin/bookmarks/master, master) Create a makefile
* 65bb417 Create a standard "hello, world" program

Mapapansin mo na ang pagtatrabaho gamit ang isang Mercurial na repositoryo ay gumagamit ng standard na git clone na utos. Ito ay dahil ang git-remote-hg ay nagtatrabaho sa isang patas na mababang antas, na gumagamit ng isang katulad na mekanismo sa kung paano ang HTTP/S protocol ng Git ay napatupad (remote na mga katulong). Dahil ang Git at Mercurial ay parehong nakadisenyo para sa bawat kliyente upang magkaroong mga isang buong kopya ng kasaysayan ng repositoryo, ang utos na ito ay gumagawa ng isang buong clone, kasama ang lahat ng kasaysayan ng proyekto, at ito ay patas na madali.

Ang log na utos ay nagpapakita ng dalawang mga commit, ang pinakabago sa mga ito ay itinuro ng buong slew ng mga ref. Kinalalabasan na ang ilan sa mga ito ay hindi aktwal na nandoon. Tingnan natin ang kung ano ang aktwal na nandoon sa .git na direktoryo:

$ tree .git/refs
.git/refs
├── heads
│   └── master
├── hg
│   └── origin
│       ├── bookmarks
│       │   └── master
│       └── branches
│           └── default
├── notes
│   └── hg
├── remotes
│   └── origin
│       └── HEAD
└── tags

9 directories, 5 files

Ang git-remote-hg ay sinusubukang gawin ang mga bagay na mas salawikaing katulad ng Git, ngunit sa ilalim nito ito ay namamahala sa konseptwal na pag-map sa pagitan ng dalawa na bahagyang magkaibang mga sistema. Ang refs/hg na direktoryo ay kung saan ang aktwal na remote na mga ref ay nakaimbak. Halimbawa, ang refs/hg/origin/branches/default ay isang Git ref na file na naglalaman ng SHA-1 na nagsisimula sa “ac7955c”, na ang commit na tinuturo ng master. Kaya ang refs/hg na direktoryo ay medyo katulad ng isang pekeng refs/remotes/origin, ngunit ito ay may nakadagdag na pagkakaiba sa pagitan ng mga bookmark at mga branch.

Ang notes/hg na file ay ang panimulang punto para sa kung paano magmapa ang git-remote-hg ng Git commit na mga hash sa mga ID ng Mercurial na changeset. Magsiyasat tayo ng kaunti:

$ cat notes/hg
d4c10386...

$ git cat-file -p d4c10386...
tree 1781c96...
author remote-hg <> 1408066400 -0800
committer remote-hg <> 1408066400 -0800

Notes for master

$ git ls-tree 1781c96...
100644 blob ac9117f...	65bb417...
100644 blob 485e178...	ac7955c...

$ git cat-file -p ac9117f
0a04b987be5ae354b710cefeba0e2d9de7ad41a9

Kaya ang refs/notes/hg ay tumuturo sa isang tree, na ang Git object na database ay isang listahan ng ibang mga object na may mga pangalan. Ang git ls-tree ay naglalabas ng mode, type, object hash, at filename para sa mga item sa loob ng isang tree. Kapag tayo ay maghuhukay sa isa sa mga item ng tree, makikita natin na ang nasa loob nito ay isang blob na nakapangalang “ac9117f” (ang SHA-1 na hash ng commit na itinuro ng master), na may mga nilalaman na “0a04b98” (na ID ng Mercurial na changeset sa dulo ng default na branch).

Ang magandang balita ay kadalasan hindi na natin kailangang mag-alala tungkol sa lahat ng mga ito. Ang tipikal na daloy ng trabaho ay hindi masyadong magkaiba mula sa pagtatrabaho sa isang Git na remote.

May isa pang bagay na dapat nating harapin bago tayo magpatuloy: mga ignore. Ang Mercurial at Git ay gumagamit ng isang sobrang katulad na mekanismo para dito, ngunit malamang na hindi mo gustong aktwal na mag-commit ng isang .gitignore na file sa isang Mercurial na repositoryo. Sa kabutihang palad, ang Git ay may isang paraan upang hindi pumansin ng mga file na lokal sa isang on-disk na repositoryo, at ang Mercurial na format ay katugma sa Git, kaya kailangan mo lang itong kopyahin:

$ cp .hgignore .git/info/exclude

Ang .git/info/exclude na file ay kumikilos katulad ng isang .gitignore, ngunit hindi kasama ang mga commit.

Workflow

Ipagpalagay natin na nakagawa tayo ng ilang trabaho at gumawa ng ilang mga commit sa master na branch, at ikaw ay handa nang i-push ito sa remote na repositoryo. Narito ang kung ano ang hitsura ng nasa ating repository ngayon:

$ git log --oneline --graph --decorate
* ba04a2a (HEAD, master) Update makefile
* d25d16f Goodbye
* ac7955c (origin/master, origin/branches/default, origin/HEAD, refs/hg/origin/branches/default, refs/hg/origin/bookmarks/master) Create a makefile
* 65bb417 Create a standard "hello, world" program

Ang ating master na branch ay nauuna ng dalawang mga commit kaysa sa origin/master, ngunit ang mga commit na iyon ay umiiral lamang sa ating lokal na makina. Tingnan natin kung may iba pa na gumagawa ng importanteng trabaho sa parehong panahon:

$ git fetch
From hg::/tmp/hello
   ac7955c..df85e87  master     -> origin/master
   ac7955c..df85e87  branches/default -> origin/branches/default
$ git log --oneline --graph --decorate --all
* 7b07969 (refs/notes/hg) Notes for default
* d4c1038 Notes for master
* df85e87 (origin/master, origin/branches/default, origin/HEAD, refs/hg/origin/branches/default, refs/hg/origin/bookmarks/master) Add some documentation
| * ba04a2a (HEAD, master) Update makefile
| * d25d16f Goodbye
|/
* ac7955c Create a makefile
* 65bb417 Create a standard "hello, world" program

Dahil nagamit natin ang --all na flag, nakikita natin ang “notes” na mga ref na panloob na ginamit ng git-remote-hg, ngunit maaari nating hindi pansinin ang mga ito. Ang iba ay katulad ng ating inaakala; ang origin/master ay lumamang ng isang commit, at ang ating kasaysayan ay humiwalay na ngayon. Hindi katulad ng ibang mga sistema na ating natrabaho sa kabanatang ito, ang Mercurial ay may kakayahang mag-asikaso ng mga merge, kaya hindi na tayo gagawa ng anumang magarbo.

$ git merge origin/master
Auto-merging hello.c
Merge made by the 'recursive' strategy.
 hello.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
$ git log --oneline --graph --decorate
*   0c64627 (HEAD, master) Merge remote-tracking branch 'origin/master'
|\
| * df85e87 (origin/master, origin/branches/default, origin/HEAD, refs/hg/origin/branches/default, refs/hg/origin/bookmarks/master) Add some documentation
* | ba04a2a Update makefile
* | d25d16f Goodbye
|/
* ac7955c Create a makefile
* 65bb417 Create a standard "hello, world" program

Perpekto. Pinatakbo natin ang mga pagsubok at ang lahat ay pumasa, kaya handa na tayong mamahagi ng ating trabaho sa natitirang bahagi ng koponan:

$ git push
To hg::/tmp/hello
   df85e87..0c64627  master -> master

Ayan yun! Kung titingnan mo ang Mercurial na repositoryo, makikita mo na ito ay gumawa ng ating inaasahan:

$ hg log -G --style compact
o    5[tip]:4,2   dc8fa4f932b8   2014-08-14 19:33 -0700   ben
|\     Merge remote-tracking branch 'origin/master'
| |
| o  4   64f27bcefc35   2014-08-14 19:27 -0700   ben
| |    Update makefile
| |
| o  3:1   4256fc29598f   2014-08-14 19:27 -0700   ben
| |    Goodbye
| |
@ |  2   7db0b4848b3c   2014-08-14 19:30 -0700   ben
|/     Add some documentation
|
o  1   82e55d328c8c   2005-08-26 01:21 -0700   mpm
|    Create a makefile
|
o  0   0a04b987be5a   2005-08-26 01:20 -0700   mpm
     Create a standard "hello, world" program

Ang changeset na nakanumerong 2 ay ginawa ng Mercurial, at ang mga changeset na nakanumerong 3 at 4 ay ginawa ng git-remote-hg, sa pamamagitan ng pag-push ng mga commit na ginawa gamit ang Git.

Mga Branch at Mga Bookmark

Ang Git ay mayroon lamang isang uri ng branch: isang reperensya na gumagalaw kapag nagawa ang mga commit. Sa Mercurial, ang uri ng reperensyang ito ay tinatawag na isang “bookmark,” at ito ay kumikilos sa masyadong parehong paraan sa isang Git na branch.

Ang konsepto ng Mercurial sa isang “branch” ay mas mabigat. Ang branch na gumawa ng isang changeset ay naitala kasama ang changeset, na nangangahulugang ito ay palaging nasa kasaysayan ng repositoryo. Narito ang isang halimbawa ng isang commit na nagawa sa develop na branch:

$ hg log -l 1
changeset:   6:8f65e5e02793
branch:      develop
tag:         tip
user:        Ben Straub <ben@straub.cc>
date:        Thu Aug 14 20:06:38 2014 -0700
summary:     More documentation

Tandaan ang linya na nagsisimula sa “branch”. Ang Git ay hindi talaga maaaring magkopya nito (ay hindi na kailangan; ang parehong mga uri ng branch ay irepresenta bilang isang Git ref), ngunit ang git-remote-hg ay kailangang maunawaan ang pagkakaiba, dahil ang Mercurial ay nagmamalasakit.

Ang paggawa ng Mercurial na mga bookmark ay kasing dali ng paglikha ng Git na mga branch. Sa panig ng Git:

$ git checkout -b featureA
Switched to a new branch 'featureA'
$ git push origin featureA
To hg::/tmp/hello
 * [new branch]      featureA -> featureA

Iyon lang lahat ang nandoon. Sa panig ng Mercurial, ito ay magmumukhang katulad nito:

$ hg bookmarks
   featureA                  5:bd5ac26f11f9
$ hg log --style compact -G
@  6[tip]   8f65e5e02793   2014-08-14 20:06 -0700   ben
|    More documentation
|
o    5[featureA]:4,2   bd5ac26f11f9   2014-08-14 20:02 -0700   ben
|\     Merge remote-tracking branch 'origin/master'
| |
| o  4   0434aaa6b91f   2014-08-14 20:01 -0700   ben
| |    update makefile
| |
| o  3:1   318914536c86   2014-08-14 20:00 -0700   ben
| |    goodbye
| |
o |  2   f098c7f45c4f   2014-08-14 20:01 -0700   ben
|/     Add some documentation
|
o  1   82e55d328c8c   2005-08-26 01:21 -0700   mpm
|    Create a makefile
|
o  0   0a04b987be5a   2005-08-26 01:20 -0700   mpm
     Create a standard "hello, world" program

Tandaan na ang bagong [featureA] na tag sa revision 5. Ang mga ito ay kumikilos na eksaktong katulad ng Git na mga branch sa panig ng Git, na may isang pagbubukod: hindi mo maaaring burahin ang isang bookmark mula sa panig ng Git (ito ay isang limitasyon ng remote na mga katulong).

Maaari ka ring magtrabaho ng isang “heavyweight” na Mercurial na branch: maglagay lamang ng isang branch sa branches na namespace:

$ git checkout -b branches/permanent
Switched to a new branch 'branches/permanent'
$ vi Makefile
$ git commit -am 'A permanent change'
$ git push origin branches/permanent
To hg::/tmp/hello
 * [new branch]      branches/permanent -> branches/permanent

Narito ang kung ano ang hitsura nito sa panig ng Mercurial:

$ hg branches
permanent                      7:a4529d07aad4
develop                        6:8f65e5e02793
default                        5:bd5ac26f11f9 (inactive)
$ hg log -G
o  changeset:   7:a4529d07aad4
|  branch:      permanent
|  tag:         tip
|  parent:      5:bd5ac26f11f9
|  user:        Ben Straub <ben@straub.cc>
|  date:        Thu Aug 14 20:21:09 2014 -0700
|  summary:     A permanent change
|
| @  changeset:   6:8f65e5e02793
|/   branch:      develop
|    user:        Ben Straub <ben@straub.cc>
|    date:        Thu Aug 14 20:06:38 2014 -0700
|    summary:     More documentation
|
o    changeset:   5:bd5ac26f11f9
|\   bookmark:    featureA
| |  parent:      4:0434aaa6b91f
| |  parent:      2:f098c7f45c4f
| |  user:        Ben Straub <ben@straub.cc>
| |  date:        Thu Aug 14 20:02:21 2014 -0700
| |  summary:     Merge remote-tracking branch 'origin/master'
[...]

Ang pangalan ng branch na “permanent” ay naitala gamit ang changeset na nakamarkang 7.

Mula sa panig ng Git, ang pagtatrabaho sa alinmang mga estilo ng branch na ito ay pareho: mag-checkout, commit, fetch, merge, pull, at push katulad ng normal mong ginagawa. Isang bagay na dapat mong malaman ay ang Mercurial ay hindi sumusuporta sa pagsusulat muli sa kasaysayan, pagdagdag lamang nito. Narito ang kung ano ang hitsura ng ating repositoryo ng Mercurial pagkatapos ng isang interactive na rebase at isang force-push:

$ hg log --style compact -G
o  10[tip]   99611176cbc9   2014-08-14 20:21 -0700   ben
|    A permanent change
|
o  9   f23e12f939c3   2014-08-14 20:01 -0700   ben
|    Add some documentation
|
o  8:1   c16971d33922   2014-08-14 20:00 -0700   ben
|    goodbye
|
| o  7:5   a4529d07aad4   2014-08-14 20:21 -0700   ben
| |    A permanent change
| |
| | @  6   8f65e5e02793   2014-08-14 20:06 -0700   ben
| |/     More documentation
| |
| o    5[featureA]:4,2   bd5ac26f11f9   2014-08-14 20:02 -0700   ben
| |\     Merge remote-tracking branch 'origin/master'
| | |
| | o  4   0434aaa6b91f   2014-08-14 20:01 -0700   ben
| | |    update makefile
| | |
+---o  3:1   318914536c86   2014-08-14 20:00 -0700   ben
| |      goodbye
| |
| o  2   f098c7f45c4f   2014-08-14 20:01 -0700   ben
|/     Add some documentation
|
o  1   82e55d328c8c   2005-08-26 01:21 -0700   mpm
|    Create a makefile
|
o  0   0a04b987be5a   2005-08-26 01:20 -0700   mpm
     Create a standard "hello, world" program

Ang mga changeset na 8, 9, at 10 ay nilikha at nabibilang sa permanent na branch, ngunit ang lumang mga changeset ay nandoon pa rin. Ito ay maaaring maging sobrang nakakalito para sa iyong mga kasamahan sa koponan na gumagamit ng Mercurial, kaya subukang iwasan ito.

Buod ng Mercurial

Ang Git at Mercurial ay sapat na magkatulad na ang pagtatrabaho sa kabuuang hangganan ay patas na hindi masakit. Kung iiwasan mo ang pagbabago ng kasaysayan na naiwan sa iyong makina (bilang pangkalahatang inirekomenda), marahil maaaring hindi mo pa alam na ang kabilang dulo ay Mercurial.

Git at Bazaar

Bukod sa DVCS, ang iba pang sikat ay ang Bazaar. Ang Bazaar ay libre at open source, at parte ng GNU Project. Ito ay kumikilos na sobrang magkaiba sa Git. Minsan, upang gumawa ng parehong bagay ng sa Git, kailangan mong gumamit ng isang ibang keyword, at ilang mga keyword na karaniwan ay walang parehong kahulugan. Sa partikular, ang pamamahala ng branch ay sobrang naiiba at maaaring magsanhi ng pagkalito, lalong lalo na kapag may isang tao na darating mula sa sansinukob ng Git. Gayunpaman, ito ay posibleng magtrabaho sa isang Bazaar na repositoryo mula sa isang Git.

May maraming mga proyekto na nagpapahintulot sa iyo na gumamit ng Git bilang isang Bazaar na kliyente. Dito ay gagamitin natin ang proyekto ni Felipe Contreras na maaari mong hanapin sa https://github.com/felipec/git-remote-bzr. Upang i-install ito, kailangan mo lang i-download ang file na git-remote-bzr sa isang folder na nilalaman sa iyong $PATH:

$ wget https://raw.github.com/felipec/git-remote-bzr/master/git-remote-bzr -O ~/bin/git-remote-bzr
$ chmod +x ~/bin/git-remote-bzr

Kailangan mo ring magkaroon ng naka-install na Bazaar. Iyon lang!

Gumawa ng isang Git na repositoryo mula sa isang Bazaar na repositoryo

Ito ay simpleng gamitin. Sapat lamang na mag-clone ng isang Bazaar na repositoryo at ipi-prefix ito gamit ang bzr::. Dahil ang Git at Bazaar ay parehong gumagawa ng buong mga clone sa iyong makina, posibleng mag-attach ng isang Git clone sa iyong lokal na Bazaar clone, ngunit hindi ito rekomendado. Mas madaling direktang i-attach ang iyong Git na clone sa isang kaparehong lugar kung saan naka-attach ang iyong Bazaar na clone ‒ ang sentral na repositoryo.

Ipagpalagay natin na ikaw ay nakapagtrabaho sa isang remote na repositoryo kung saan nasa address na bzr+ssh://developer@mybazaarserver:myproject.

$ git clone bzr::bzr+ssh://developer@mybazaarserver:myproject myProject-Git
$ cd myProject-Git

Sa puntong ito, ang iyong Git na repositoryo ay nabuo ngunit hindi nakasiksik para sa paggamit ng optimal disk. Kaya nga kailangan mo ring linisin at isiksik ang iyong Git na repositoryo, lalo na kung ito ay malaki:

$ git gc --aggressive

Bazaar na mga branch

Ang Bazaar ay nagpapahintulot lamang sa iyo na mag-clone ng mga branch, ngunit ang isang repositoryo ay maaaring maglaman ng iilang mga branch, at ang git-remote-bzr ay maaaring mag-clone ng pareho. Halimbawa, upang mag-clone ng isang branch:

$ git clone bzr::bzr://bzr.savannah.gnu.org/emacs/trunk emacs-trunk

At upang mag-clone ng buong repositoryo:

$ git clone bzr::bzr://bzr.savannah.gnu.org/emacs emacs

Ang pangalawang utos ay iko-clone ang lahat ng mga branch na nilalaman sa emacs na repositoryo; gayunpaman posibleng tumuro sa ilang mga branch:

$ git config remote-bzr.branches 'trunk, xwindow'

Ilang remote na mga repositoryo ay hindi nagpapahintulot sa iyo na maglista ng kanilang mga branch, sa kasong manu-mano mong tukuyin ang mga iyon, at kahit na maaari mong tukuyin ang kompigurasyon sa pag-clone na utos, maaaring mas madali ito para sa iyo:

$ git init emacs
$ git remote add origin bzr::bzr://bzr.savannah.gnu.org/emacs
$ git config remote-bzr.branches 'trunk, xwindow'
$ git fetch

Huwag pansinin ang kung ano ang hindi pinansin gamit ang .bzrignore

Dahil ikaw ay nagtatrabaho sa isang proyekto na pinamamahalaan ng Bazaar, hindi ka dapat gumawa ng isang .gitignore na file dahil maaari mong aksidenteng matakda ito sa ilalim ng version control at ang ibang mga tao na nagtatrabaho gamit ang Bazaar ay magagambala. Ang solusyon ay ang paglikha ng .git/info/exclude na file alinman bilang isang simbolikong link o bilang isang regular na file. Tingnan natin mamaya kung paano lutasin ang tanong na ito.

Ang Bazaar ay gumagamit ng parehong modela sa Git upang hindi magpansin ng mga file, ngunit mayroon ding dalawang mga tampok na walang isang katumbas sa Git. Ang kumpletong deskripsyon ay maaaring matagpuan sa the documentation. Ang dalawang mga tampok ay:

  1. Ang "!!" ay nagpapahintulot sa iyo na hindi pumansin sa tiyak na mga pattern ng file kahit na ang mga ito ay nakatukoy gamit ang isang "!" na panuntunan.

  2. Ang "RE:" sa unahan ng isang linya ay nagpapahintulot sa iyo upang tumukoy ng isang Python regular expression (Ang Git ay nagpapahintulot lamang ng mga shell glob).

Bilang isang kalalabasan, mayroong dalawang magkaibang mga sitwasyon na isaalang-alang:

  1. Kung ang .bzrignore na file ay hindi naglalaman ng anuman sa dalawang tiyak na mga prefix na ito, pagkatapos ay maaari kang simpleng gumawa ng isang simbolikong link nito sa repositoryo: ln -s .bzrignore .git/info/exclude

  2. Kung hindi man, dapat kang lumikha ng .git/info/exclude na file at iangkop ito upang hindi pansinin ang eksaktong parehong mga file sa .bzrignore.

Kahit ano pa ang kaso, kailangan mong manatiling mapagbantay laban sa anumang pagbabago ng .bzrignore upang siguraduhin na ang .git/info/exclude na file ay palaging sumasalamin sa .bzrignore. Sa katunayan, kung ang .bzrignore na file ay magbabago at naglalaman ng isa o higit pang mga linya na nagsisimula ng "!!" o "RE:", ang Git na hindi kayang interpretahin ang mga linyang ito, kailangan mong iangkop ang iyong .git/info/exclude na file upang hindi pansinin ang parehong mga file bilang mga hindi pinansin gamit ang .bzrignore. Bukod dito, kung ang .git/info/exclude na file ay isang simbolikong link, kailangan mo munang burahin ang simbolikong link, kopyahin ang .bzrignore sa .git/info/exclude at pagkatapos ay iangkop ang huli. Gayunpaman, mag-ingat sa paglikha nito dahil gamit ang Git ito ay imposibleng muling isama ang isang file kung ang isang magulang na direktoryo sa file na iyon ay hindi kasama.

I-fetch ang mga pagbabago ng remote na repositoryo

Upang mag-fetch ng mga pagbabago ng remote, magpu-pull ka ng mga pagbabago tulad ng dati, gamit ang Git na mga utos. Kung kaya ang iyong mga pagbabago ay nasa master na branch, i-merge o i-rebase ang iyong trabaho sa origin/master na branch:

$ git pull --rebase origin

I-push ang iyong trabaho sa remote na repositoryo

Dahil ang Bazaar rin ay may konsepto ng merge na mga commit, walang problema kung ikaw ay mag-push ng isang merge na commit. Kaya maaari kang magtrabaho sa isang branch, i-merge ang mga pagbabago sa master at i-push ang iyong trabaho. Pagkatapos, gumawa ka ng iyong mga branch, subukan at i-commit mo ang iyong trabaho gaya ng dati. Sa huli ay i-push mo ang iyong trabaho sa Bazaar na reporsitoryo:

$ git push origin master

Mga Paunawa

Ang balangkas ng mga remote-helper ng Git ay may ilang mga limitasyon na nalalapat. Sa partikular, ang mga utos na ito ay hindi gagana:

  • git push origin :branch-to-delete (Ang Bazaar ay hindi maaaring tumanggap ng pagbubura ng ref sa ganitong paraan.)

  • git push origin old:new (ipu-push nito ang old)

  • git push --dry-run origin branch (ito ay magpu-push)

Buod

Dahil katulad ang mga modelo ng Git at Bazaar, may hindi medyo maraming paglalaban kapag nagtatrabaho sa kabuuan ng hangganan. Hangga’t ikaw ay nagmamasid para sa mga limitasyon, at palaging may kamalayan na ang remote na repositoryo ay hindi katutubong Git, ikaw ay magiging maayos lamang.

Git at Perforce

Ang Perforce ay isang sobrang popular na sistema ng version-control sa korporasyong mga environment. Ito ay nasa paligid na mula 1995, na ginagawa itong pinakalumang sistema na natalakay sa kabanatang ito. Tulad nito, ito’y dinisenyo gamit ang ang mga hadlang sa panahon nito; ito ay nagpapalagay na palagi kang konektado sa isang solong sentral na server, at isang beryon lamang ang pinapanatili sa lokal na disk. Upang maging sigurado, ang mga tampok at mga hadlang nito ay akma sa iilang tiyak na mga problema, ngunit may maraming mga proyekto na gumagamit ng Perforce kung saan ang Git ay aktwal na mas maayos na gumagana.

Mayroong dalawang mga opsyon kung gusto mong paghaluin ang iyong paggamit ng Perforce at Git. Ang nauuna na tatalakayin natin ay ang “Git Fusion” na tulay mula sa mga marka ng Perforce, na nagpapahintulot sa iyo na ilantad ang mga subtree ng iyong Perforce depot bilang read-write na mga repositoryo ng Git. Ang pangalawa ay ang git-p4, isang client-side na tulay na hahayaan kang gumamit ng Git bilang isang Perforce na kliyente, nang hindi nangangailangan ng anumang muling pagsasaayos ng Perforce server.

Pagsasanib ng Git

Ang Perforce ay nagbibigay ng isang produkto na tinatawag na Pagsasanib ng Git (makukuha sa http://www.perforce.com/git-fusion), na pinagsasabay ang isang Perforce na server sa Git na mga repositoryo sa panig ng server.

Pag-set Up

Para sa ating mga halimbawa, gagamit tayo ng pinakamadaling pag-install na pamamaraan para sa Git Fusion, na nagda-donwload ng isang virtual na makina na nagpapatakbo ng Perforce daemon at Git Fusion. Maaari mong kunin ang imahe ng virtual na makina mula sa http://www.perforce.com/downloads/Perforce/20-User, at kapag ito ay natapos nang mag-download, i-import ito sa iyong paboritong virtualization na software (gagamit tayo ng VirtualBox).

Sa unang pagsisimula sa makina, tatanungin ka nito na i-customize ang password para sa tatlong Linux na mga gumagamit (root, perforce, at git), at magbigay ng isang instance na pangalan, na maaaring gamitin upang makilala ang pag-install na ito mula sa mga iba sa parehong network. Kapag nakumpleto ng iyon ang lahat, makikita mo ito:

Ang boot screen ng virtual na makina ng Git Fusion.
Figure 146. Ang boot screen ng virtual na makina ng Git Fusion

Dapat mong tandaan ang IP address na ipinakita dito, gagamitin natin ito mamaya. Susunod, lilikha tayo ng isang Perforce na gumagamit. Piliin ang “Login” na opsyon sa ibaba at pindutin ang enter (o SSH sa makina), at mag-log in bilang root. Pagkatapos ay gamitin ang mga utos na ito upang lumikha ng isang gumagamit:

$ p4 -p localhost:1666 -u super user -f john
$ p4 -p localhost:1666 -u john passwd
$ exit

Ang nauuna ay magbubukas ng isang VI na editor upang i-customize ang gumagamit, ngunit maaari mong tanggapin ang mga default sa pamamagitan ng pag-type ng :wq at pagpindot ng enter. Ang pangalawa ay didiktahan kang magpasok ng isang password nang dalawang beses. Iyan lahat ang kakailanganing gawin natin sa isang shell prompt, kaya lumabas sa sesyon.

Ang sunod na bagay na kakailanganing gawin upang sumunod ay sabihan ang Git na huwang patunayan ang SLL na mga sertipiko. Ang Git Fushion na imahe ay nagsasama ng isang sertipiko, ngunit ito ay para sa isang domain na hindi tutugma sa iyong IP address ng virtual na makina, kaya ang Git ay tatanggihan ang HTTPS na koneksyon. Kung ito ay magiging isang permanenteng pag-install, konsultahin ang Perforce Git Fusion na manwal upang mag-install ng isang naiibang sertipiko; para sa mga hangarin ng ating halimbawa, ito ay sapat lamang:

$ export GIT_SSL_NO_VERIFY=true

Ngayon maaari nating subukan na ang lahat ay gumagana.

$ git clone https://10.0.1.254/Talkhouse
Cloning into 'Talkhouse'...
Username for 'https://10.0.1.254': john
Password for 'https://john@10.0.1.254':
remote: Counting objects: 630, done.
remote: Compressing objects: 100% (581/581), done.
remote: Total 630 (delta 172), reused 0 (delta 0)
Receiving objects: 100% (630/630), 1.22 MiB | 0 bytes/s, done.
Resolving deltas: 100% (172/172), done.
Checking connectivity... done.

Ang virtual-machine na imahe ay dumarating nang may kasangkapan na isang halimbawang proyekto na maaari mong i-clone. Dito tayo ay nagko-clone sa HTTPS, gamit ang john na gumagamit na ginawa natin sa itaas; ang Git ay magtatanong para sa mga kredensyal para sa koneksyong ito, ngunit ang kredensyal na cache ay papayagan tayong lumaktaw sa hakbang na ito para sa anumang kasunod na mga kahilingan.

Kumpigurasyon ng Fusion

Kapag na-install mo na ang Git Fusion, gugustuhin mong i-tweak ang kumpigurasyon. Ito ay talagang patas na madaling gawin gamit ang iyong paboritong Perforce na kliyente; i-mapa lamang ang //.git-fusion na direktoryo sa server ng Perforce patungo sa iyong workspace. Ang istraktura ng file ay magmumukhang katulad nito:

$ tree
.
├── objects
│   ├── repos
│   │   └── [...]
│   └── trees
│       └── [...]
│
├── p4gf_config
├── repos
│   └── Talkhouse
│       └── p4gf_config
└── users
    └── p4gf_usermap

498 directories, 287 files

Ang objects na direktoryo ay panloob na ginagamit ng Git Fusion upang i-mapa ang mga bagay ng Perforce sa Git at kabaligtaran, hindi mo na kailangang guluhin ang anumang nandoon. May isang global na p4gf_config na file sa direktoryong ito, pati na rin sa bawat repositoryo – ang mga ito ay kumpigurasyon na mga file na tumutukoy kung paano kumikilos ang Git Fusion. Tingnan natin ang file sa root:

[repo-creation]
charset = utf8

[git-to-perforce]
change-owner = author
enable-git-branch-creation = yes
enable-swarm-reviews = yes
enable-git-merge-commits = yes
enable-git-submodules = yes
preflight-commit = none
ignore-author-permissions = no
read-permission-check = none
git-merge-avoidance-after-change-num = 12107

[perforce-to-git]
http-url = none
ssh-url = none

[@features]
imports = False
chunked-push = False
matrix2 = False
parallel-push = False

[authentication]
email-case-sensitivity = no

Hindi na tayo pumasok pa sa mga kahulugan ng mga flag na ito dito, ngunit tandaan na ito ay isang INI-formatted text na file lamang, masyadong katulad ng ginigamit ng Git para sa kumpigurasyon. Ang file na ito ay tinutukoy ang global na mga opsyon, na maaaring i-override ng mga file na repository-specific na kumpigurasyon, katulad ng repos/Talkhouse/p4gf_config. Kung bubuksan mo ang file na ito, makikita mo ang isang [@repo] na seksyon na may ilang mga setting na naiiba sa global na mga default. Makikita mo rin ang mga seksyon na nagmumukhang katulad nito:

[Talkhouse-master]
git-branch-name = master
view = //depot/Talkhouse/main-dev/... ...

Ito ay isang pagmapa sa pagitan ng isang Perfoce na branch at isang Git na branch. Ang seksyon ay maaaring pangalanan sa kung anuman ang gugustuhin mo, hangga’t ang pangalan ay natatangi. Ang git-branch-name ay hahayaan kang palitan ang isang depot na landas na maaaring maging masalimuot sa ilalim ng Git ng isang mas palakaibigan na pangalan. Ang view na setting ay namamahala kung paano namapa ang mga file ng Perforce sa Git na repositoryo, gamit ang syntax ng standard view ng pagmapa. Higit pa sa isang pagmapa ang maaaring matukoy, kagaya ng halimbawang ito:

[multi-project-mapping]
git-branch-name = master
view = //depot/project1/main/... project1/...
       //depot/project2/mainline/... project2/...

Sa paraang ito, kung ang iyong normal na pagmapa ng workspace ay nagsasama ng mga pagbabago sa istraktura ng mga direktoryo, maaari mong kopyahin iyon gamit ang isang Git na repositoryo.

Ang huling file na tatalakayin natin ay ang users/p4gf_usermap, na nagmamapa ng Perforce na mga gumagamit, at maaaring hindi mo na kakailanganin. Kapag ikaw ay ng nagpapalit mula sa isang Perforce na changeset patungo sa isang Git na commit, ang default na pag-uugali ng Git Fusion ay ang paghahanap sa Perforce na gumagamit, at gagamit ng email address at buong pangalan na naka-imbak doon para sa may-akda/taga-commit na patlang sa Git. Kapag nagpapalit sa ibang paraan, ang default ay ang paghahanap ng Perforce na gumagamit na may email address na naka-imbak sa may-akda na field ng Git na commit, at isusumite ang changeset bilang gumagamit na iyon (na may mga permiso na inilalapat). Sa karamihang mga kaso, ang pag-uugaling ito ay maayos lamang, ngunit isaalang-alang ang sumusunod na pagmapa na file:

john john@example.com "John Doe"
john johnny@appleseed.net "John Doe"
bob employeeX@example.com "Anon X. Mouse"
joe employeeY@example.com "Anon Y. Mouse"

Ang bawat linya ay naka-format na <user> <email> "<full name>", at lumilikha ng isang solong gumagamit na pagmapa. Ang unang dalawang mga linya ay nagmamapa ng dalawang naiibang mga email address sa parehong Perforce user na account. Ito ay kapaki-pakinabang kung ikaw ay nakagawa ng Git na mga commit sa ilalim ng ilang magkaibang mga email address (o nagbago ng mga email address), ngunit gusto silang mamapa sa parehong Perforce na gumagamit. Kapag lumilikha ng isang Git na commit mula sa isang Perforce na changeset, ang unang linya na tumutugma sa Perforce na gumagamit ay gagamitin para sa impormasyon ng Git authorship.

Ang huling dalawang mga linya ay nagmamaskara sa aktwal na mga pangalan at mga email address nina Bob at Joe mula sa Git na mga commit na nilikha. Ito ay maganda kung gusto mong mag-open-source ng isang panloob na proyekto, ngunit hindi gustong i-publish ang iyong employee na direktoryo sa buong mundo. Tandaan na ang mga email address at buong mga pangalan ay dapat natatangi, maliban kung gusto mong ipalagay ang lahat ng Git na mga commit sa isang solong kathang-isip na may-akda.

Workflow

Ang Git Fusion ng Perforce ay isang dalawang-daanan na tulay sa pagitan ng Perfoce at Git na version control. Tingnan natin kung ano ang pakiramdam sa pagtatrabaho mula sa panig ng Git. Ating ipalagay na nagmapa tayo sa “Jam” na proyekto gamit ang isang kumpigurasyon na file na ipinakita sa itaas, na maaari nating i-clone katulad nito:

$ git clone https://10.0.1.254/Jam
Cloning into 'Jam'...
Username for 'https://10.0.1.254': john
Password for 'https://john@10.0.1.254':
remote: Counting objects: 2070, done.
remote: Compressing objects: 100% (1704/1704), done.
Receiving objects: 100% (2070/2070), 1.21 MiB | 0 bytes/s, done.
remote: Total 2070 (delta 1242), reused 0 (delta 0)
Resolving deltas: 100% (1242/1242), done.
Checking connectivity... done.
$ git branch -a
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/master
  remotes/origin/rel2.1
$ git log --oneline --decorate --graph --all
* 0a38c33 (origin/rel2.1) Create Jam 2.1 release branch.
| * d254865 (HEAD, origin/master, origin/HEAD, master) Upgrade to latest metrowerks on Beos -- the Intel one.
| * bd2f54a Put in fix for jam's NT handle leak.
| * c0f29e7 Fix URL in a jam doc
| * cc644ac Radstone's lynx port.
[...]

Sa unang pagkakataon na gagawin natin ito, maaari itong magtagal ng ilang saglit. Ang nangyayari ay ang Git Fusion ay nagpapalit sa lahat ng naaangkop na mga changeset sa kasaysayan ng Perforce patungo sa Git na mga commit. Ito ay lokal na nangyayari sa server, kaya ito ay relatibong mabilis, ngunit kung mayroon kang maraming kasaysayan, maaari rin itong tumagal ng ilang sandali. Ang kasunod na mga fetch ay gumagawa ng incremental na pagpapalit, kaya ito ay nararamdaman na mas katulad sa likas na bilis ng Git.

Batay sa iyong nakikita, ang ating repositoryo ay namumukhang eksaktong katulad ng ibang Git na repositoryo na maaari mong trabahuan. Mayroong tatlong mga branch, at ang Git ay nakakatulong na gumawa ng isang lokal na master na branch na sumusubaybay sa origin/master. Gumawa tayo ng kaunting trabaho, at lumikha ng ilang bagong mga commit:

# ...
$ git log --oneline --decorate --graph --all
* cfd46ab (HEAD, master) Add documentation for new feature
* a730d77 Whitespace
* d254865 (origin/master, origin/HEAD) Upgrade to latest metrowerks on Beos -- the Intel one.
* bd2f54a Put in fix for jam's NT handle leak.
[...]

Mayroon tayong dalawang bagong mga commit. Ngayon suriin natin kung may ibang taong nagtatrabaho:

$ git fetch
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 2), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From https://10.0.1.254/Jam
   d254865..6afeb15  master     -> origin/master
$ git log --oneline --decorate --graph --all
* 6afeb15 (origin/master, origin/HEAD) Update copyright
| * cfd46ab (HEAD, master) Add documentation for new feature
| * a730d77 Whitespace
|/
* d254865 Upgrade to latest metrowerks on Beos -- the Intel one.
* bd2f54a Put in fix for jam's NT handle leak.
[...]

Mukhang mayroon nga! Hindi mo na kailangang malaman ito mula sa pananaw na ito, ngunit ang 6afeb15 na commit ay aktwal na nilikha gamit ang isang Perforce na kliyente. Ito ay magmumukha lamang na ibang commit mula sa pananaw ng Git, na eksakto ang punto. Tingnan natin kung paano nakikitungo ang Perforce na server sa isang merge na commit:

$ git merge origin/master
Auto-merging README
Merge made by the 'recursive' strategy.
 README | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
$ git push
Counting objects: 9, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (9/9), done.
Writing objects: 100% (9/9), 917 bytes | 0 bytes/s, done.
Total 9 (delta 6), reused 0 (delta 0)
remote: Perforce: 100% (3/3) Loading commit tree into memory...
remote: Perforce: 100% (5/5) Finding child commits...
remote: Perforce: Running git fast-export...
remote: Perforce: 100% (3/3) Checking commits...
remote: Processing will continue even if connection is closed.
remote: Perforce: 100% (3/3) Copying changelists...
remote: Perforce: Submitting new Git commit objects to Perforce: 4
To https://10.0.1.254/Jam
   6afeb15..89cba2b  master -> master

Ang Git ay iisiping ito ay gumagana. Tingnan natin ang kasaysayan ng README na file mula sa pananaw ng Perforce, gamit ang tampok na revision graph ng p4v:

Revision graph ng Perforce na resulta mula sa Git push.
Figure 147. Revision graph ng Perforce na resulta mula sa Git push.

Kung hindi ka pa nakakakita ng ganitong pananaw dati, ito ay maaaring magmistulang nakakalito, ngunit ito ay nagpapakita ng parehong mga konsepto bilang isang grapikal na viewer para sa kasaysayan ng Git. Tayo ay tumitingin sa kasaysayan ng README na file, kaya ang direktoryo na tree sa kaliwang itaas ay nagpapakita lamang ng file habang ito ay lumutang sa magkaibang mga branch. Sa kanang itaas, mayroon tayong isang biswal na graph ng paano ang magkaibang mga revision ng file ay nauugnay, at ang malaking larawan na pananaw sa graph na ito sa kanang ibaba. Ang natitirang pananaw ay binigay sa mga detalye na pananaw para sa napiling revision (2 sa kasong ito).

Isang bagay na pansinin ay ang graph ay nagmumukhang eksaktong katulad ng isa na nasa kasaysayan ng Git. Ang Perforce ay hindi nagkaroon ng isang nakapangalang branch para iimbak ang 1 at 2 na mga commit, kaya ito ay gumawa ng isang “anonymous” na branch sa .git-fusion na direktoryo upang panghawakan ito. Ito rin ay mangyayari para sa nakapangalang mga branch ng Git na hindi tumutugma sa isang nakapangalang Perforce na branch (at maaari mong i-mapa mamaya ang mga iyon sa isang Perforce na branch gamit ang kumpigurasyon na file).

Karamihan sa ito ay nangyayari sa likod na mga eksena, ngunit ang huling resulta ay ang isang tao sa isang koponan ay maaaring gumagamit ng Git, ang iba pa ay gumagamit ng Perforce, at ni isa sa kanila ay hindi malalaman ang tungkol sa pinili ng isa.

Buod ng Git-Fusion

Kung ikaw ay mayroong (o maaaring makakuha ng) access sa iyong Perforce na server, ang Git Fusion ay isang dakilang paraan upang ganap na papag-usapin sa isa’t isa ang Git at Perforce. Mayroong kauting kumpigurasyon na kasangkot, ngunit ang pag-aaral ay hindi masyadong matarik. Ito ay isa sa ilang mga seksyon sa kabanatang ito kung saan ang pag-iigat tungkol sa paggamit ng buong kapangyarihan ng Git ay hindi magpapakita. Hindi nito sinasabi na ang Perforce ay magiging masaya sa lahat ng tinatapon sa ito – kung susubukan mong isulat muli ang kasaysayan na na-push na, tatanggihan ito ng Git Fusion – ngunit matiyagang susubukan ng Git Fusion na magramdam na likas. Maaari mo ring gamitin ang Git na mga submodule (bagaman ang mga iyon ay magmumukhang kakaiba sa Perforce na mga gumagamit), at mag-merge ng mga branch (ito ay itatala bilang isang integrasyon sa panig ng Perforce).

Kung hindi ka makakumbinsi sa tagapangasiwa ng iyong server na i-set up ang Git Fusion, mayroon pa ring paraan upang kasamang magamit ang mga kasangkapang ito.

Git-p4

Ang Git-p4 ay isang dalawang-daanan na tulay sa pagitan ng Git at Perforce. Ito ay buong tumatakbo sa loob ng iyong Git na repositoryo, kaya hindi ka na mangangailangang mag-access pa sa Perforce na server (iba kaysa sa user na mga kredensyal, syempre). Ang Git-p4 ay hindi mas umaangkop o kukumpleto sa isang solusyon kagaya ng Git Fusion, ngunit hindi nito pinapayagang gumawa ka pa ng karamihan sa kung ano ang gusto mong gawin nang hindi nagsasalakay sa server na environment.

Kakailanganin mo ang p4 na kagamitan sa kung saanman sa iyong PATH upang magtrabaho sa git-p4. Batay sa kasulatang ito, ito ay libreng nakukuha sa http://www.perforce.com/downloads/Perforce/20-User.

Pag-set Up

Para sa mga layunin ng halimbawa, papatakbuhin mo ang Perforce na server mula sa Git Fusion na OVA ayon sa nakita sa itaas, ngunit iiwasan natin ang Git Fusion na server at direktang pumunta sa Perforce na version control.

Upang magamit ang p4 na command-line na kliyente (kung saan nakadepende ang git-p4), kakailanganin mong magtakda ng dalawang environment na mga variable:

$ export P4PORT=10.0.1.254:1666
$ export P4USER=john
Pagsisimula

Batay sa anuman sa Git, ang unang utos ay ang pag-clone:

$ git p4 clone //depot/www/live www-shallow
Importing from //depot/www/live into www-shallow
Initialized empty Git repository in /private/tmp/www-shallow/.git/
Doing initial import of //depot/www/live/ from revision #head into refs/remotes/p4/master

Ito ay lumilikha ng kung ano ang tinatawag ng Git na isang “mababaw” na clone; ang pinakakamakailan lamang na rebisyon ng Perforce ang na-import sa Git; tandaan, ang Perforce ay hindi nakadisenyo upang magbigay ng bawat rebisyon sa bawat gumagamit. Ito ay sapat upang gumamit ng Git bilang isang Perforce na kliyente, ngunit para sa ibang mga layunin ito ay hindi pa sapat.

Kapag ito ay natapos, mayroon tayong isang buong functional na repositoryo ng Git:

$ cd myproject
$ git log --oneline --all --graph --decorate
* 70eaf78 (HEAD, p4/master, p4/HEAD, master) Initial import of //depot/www/live/ from the state at revision #head

Tandaan kung paano nagkaroon ng isang “p4” na remote para sa Perforce na server, ngunit ang lahat ng iba ay magmumukhang katulad ng isang standard na clone. Sa katunayan, ito ay medyo nakakalinlang; walang aktwal na remote doon.

$ git remote -v

Wala talagang mga remote na umiiral sa repositoryong ito. Ang Git-p4 ay lumikha ng ilang mga ref upang magrepresenta sa estado ng server, at sila ay magmumukhang katulad ng remote na mga ref sa git log, ngunit sila ay hindi pinamamahalaan ng Git, hindi mo maaaring i-push ang mga ito.

Workflow

Sige, gumawa tayo ng ilang trabaho. Ipalagay natin na ikaw ay gumawa ng ilang pag-unlad sa isang sobrang importanteng tampok, at handa ka nang ipakita ito sa natitirang bahagi ng iyong koponan.

$ git log --oneline --all --graph --decorate
* 018467c (HEAD, master) Change page title
* c0fb617 Update link
* 70eaf78 (p4/master, p4/HEAD) Initial import of //depot/www/live/ from the state at revision #head

Tayo ay gumawa ng dalawang bagong mga commit na handa nating isumite sa Perforce na server. Suriin natin kung may ibang taong nagtatrabaho ngayong araw na ito:

$ git p4 sync
git p4 sync
Performing incremental import into refs/remotes/p4/master git branch
Depot paths: //depot/www/live/
Import destination: refs/remotes/p4/master
Importing revision 12142 (100%)
$ git log --oneline --all --graph --decorate
* 75cd059 (p4/master, p4/HEAD) Update copyright
| * 018467c (HEAD, master) Change page title
| * c0fb617 Update link
|/
* 70eaf78 Initial import of //depot/www/live/ from the state at revision #head

Mukhang sila nga, at ang master at p4/master ay magkahiwalay. Ang sistema ng pag-branch ng Perforce ay walang katulad sa Git, kaya ang pagsumite ng merge na mga commit ay hindi gumagawa ng kahulugan. Ang Git-p4 ay nagrerekomenda na mag-rebase ka ng iyong mga commit, at nagsasama rin ng isang shortcut upang gumawa nito:

$ git p4 rebase
Performing incremental import into refs/remotes/p4/master git branch
Depot paths: //depot/www/live/
No changes to import!
Rebasing the current branch onto remotes/p4/master
First, rewinding head to replay your work on top of it...
Applying: Update link
Applying: Change page title
 index.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Marahil ay maaari mong masabi batay sa output, ngunit ang git p4 rebase ay isang shortcut para sa git p4 sync na sinusundan ng git rebase p4/master. Ito ay medyo mas matalino kaysa sa iyon, lalo na kung ikaw ay nagtatrabaho sa maramihang mga branch, ngunit ito ay isang magandang pagtatantya.

Ngayon ang ating kasaysayan ay linear na ulit, at handa na tayong mag-ambag ng ating mga pagbabago pabalik sa Perforce. Ang git p4 submit na utos ay susubukang lumikha ng isang bagong rebisyon ng Perforce para sa bawat Git na commit sa pagitan ng p4/master at master. Ang pagpapatakbo nito ay ihuhulog tayo sa ating paboritong editor, at ang mga nilalaman ng file ay magmumukhang kagaya nito:

# A Perforce Change Specification.
#
#  Change:      The change number. 'new' on a new changelist.
#  Date:        The date this specification was last modified.
#  Client:      The client on which the changelist was created.  Read-only.
#  User:        The user who created the changelist.
#  Status:      Either 'pending' or 'submitted'. Read-only.
#  Type:        Either 'public' or 'restricted'. Default is 'public'.
#  Description: Comments about the changelist.  Required.
#  Jobs:        What opened jobs are to be closed by this changelist.
#               You may delete jobs from this list.  (New changelists only.)
#  Files:       What opened files from the default changelist are to be added
#               to this changelist.  You may delete files from this list.
#               (New changelists only.)

Change:  new

Client:  john_bens-mbp_8487

User: john

Status:  new

Description:
   Update link

Files:
   //depot/www/live/index.html   # edit


######## git author ben@straub.cc does not match your p4 account.
######## Use option --preserve-user to modify authorship.
######## Variable git-p4.skipUserNameCheck hides this message.
######## everything below this line is just the diff #######
--- //depot/www/live/index.html  2014-08-31 18:26:05.000000000 0000
+++ /Users/ben/john_bens-mbp_8487/john_bens-mbp_8487/depot/www/live/index.html   2014-08-31 18:26:05.000000000 0000
@@ -60,7 +60,7 @@
 </td>
 <td valign=top>
 Source and documentation for
-<a href="http://www.perforce.com/jam/jam.html">
+<a href="jam.html">
 Jam/MR</a>,
 a software build tool.
 </td>

Ito ay kadalasang magkapareho sa nilalaman na iyong nakikita sa pagpapatakbo ng p4 submit, maliban sa bagay sa huli na nakakatulong na idinagdag ng git-p4. Ang Git-p4 ay susubukang isa-isang parangalan ang iyong Git at Perforce na mga setting kapag kailangan nitong magbigay ng isang pangalan para sa isang commit o changeset, ngunit sa ilang kaso gusto mong i-override ito. Halimbawa, kung ang Git na commit na iyong ini-import ay naisulat ng isang taga-ambag na walang isang Perforce user na account, maaaring gugustuhin mo rin ang resultang changeset na magmukhang isinulat nila (hindi ikaw).

Ang Git-p4 ay nakakatulong na nag-import ng mensahe mula sa Git na commit bilang nilalaman para sa Perforce na changeset na ito, kaya ang lahat na kailangan nating gawin ay ang pag-save at umalis, dalawang beses (para sa bawat commit). Ang resultang shell na output ay magmumukhang kagaya nito:

$ git p4 submit
Perforce checkout for depot path //depot/www/live/ located at /Users/ben/john_bens-mbp_8487/john_bens-mbp_8487/depot/www/live/
Synchronizing p4 checkout...
... - file(s) up-to-date.
Applying dbac45b Update link
//depot/www/live/index.html#4 - opened for edit
Change 12143 created with 1 open file(s).
Submitting change 12143.
Locking 1 files ...
edit //depot/www/live/index.html#5
Change 12143 submitted.
Applying 905ec6a Change page title
//depot/www/live/index.html#5 - opened for edit
Change 12144 created with 1 open file(s).
Submitting change 12144.
Locking 1 files ...
edit //depot/www/live/index.html#6
Change 12144 submitted.
All commits applied!
Performing incremental import into refs/remotes/p4/master git branch
Depot paths: //depot/www/live/
Import destination: refs/remotes/p4/master
Importing revision 12144 (100%)
Rebasing the current branch onto remotes/p4/master
First, rewinding head to replay your work on top of it...
$ git log --oneline --all --graph --decorate
* 775a46f (HEAD, p4/master, p4/HEAD, master) Change page title
* 05f1ade Update link
* 75cd059 Update copyright
* 70eaf78 Initial import of //depot/www/live/ from the state at revision #head

Ang resulta ay bagaman gumawa lamang tayo ng isang git push, na ang pinakamalapit na analohiya sa kung ano ang akwal na nangyari.

Tandaan na sa panahon ng prosesong ito ang bawat Git na commit ay naging isang Perforce na changeset; kung gusto mong isiksik ang mga ito patungo sa isang solong changeset, maaari mong gawin iyon gamit ang isang interactive na rebase bago sa pagpapatakbo ng git p4 submit. Tandaan din na ang SHA-1 na mga hash ng lahat ng mga commit na nasumite bilang mga changeset ay nabago; ito ay dahil ang git-p4 ay nagdaragdag ng isang linya sa hulihan ng bawat commit na pinapalitan nito:

$ git log -1
commit 775a46f630d8b46535fc9983cf3ebe6b9aa53145
Author: John Doe <john@example.com>
Date:   Sun Aug 31 10:31:44 2014 -0800

    Change page title

    [git-p4: depot-paths = "//depot/www/live/": change = 12144]

Ano ang mangyayari kung susubukang mong magsumite ng isang merge na commit? Subukan natin ito. Narito ang sitwasyon na kung saan tayo ay napunta:

$ git log --oneline --all --graph --decorate
* 3be6fd8 (HEAD, master) Correct email address
*   1dcbf21 Merge remote-tracking branch 'p4/master'
|\
| * c4689fc (p4/master, p4/HEAD) Grammar fix
* | cbacd0a Table borders: yes please
* | b4959b6 Trademark
|/
* 775a46f Change page title
* 05f1ade Update link
* 75cd059 Update copyright
* 70eaf78 Initial import of //depot/www/live/ from the state at revision #head

Ang kasaysayan ng Git at Perforce ay naghihiwalay pagkatapos ng 775a46f. Ang panig ng Git ay mayroong dalawang mga commit, pagkatapos ay ang isang merge na commit na may Perforce na ulo, pagkatapos ay ibang commit. Susubukan nating magsumite ng mga ito sa ibabaw ng isang solong changeset sa panig ng Perforce. Tingnan natin kung ano ang mangyayari kung susubukan nating magsumite ngayon:

$ git p4 submit -n
Perforce checkout for depot path //depot/www/live/ located at /Users/ben/john_bens-mbp_8487/john_bens-mbp_8487/depot/www/live/
Would synchronize p4 checkout in /Users/ben/john_bens-mbp_8487/john_bens-mbp_8487/depot/www/live/
Would apply
  b4959b6 Trademark
  cbacd0a Table borders: yes please
  3be6fd8 Correct email address

Ang -n na flag ay maikli para sa --dry-run, na sumusubok na mag-ulat kung ano ang mangyayari kung ang pagsumite na utos ay napatakbo sa katunayan. Sa kasong ito, ito ay magmumukhang katulad ng nilikha nating tatlong Perforce na mga changeset, na tumutugma sa tatlong non-merge na mga commit na hindi pa umiiral sa Perforce na server. In this case, it looks like we’d be creating three Perforce changesets, which correspond to the three non-merge commits that don’t yet exist on the Perforce server. Iyon ay parang katunog ng eksaktong gusto natin, tingnan natin kung paano ang kinalalabasan nito:

$ git p4 submit
[…]
$ git log --oneline --all --graph --decorate
* dadbd89 (HEAD, p4/master, p4/HEAD, master) Correct email address
* 1b79a80 Table borders: yes please
* 0097235 Trademark
* c4689fc Grammar fix
* 775a46f Change page title
* 05f1ade Update link
* 75cd059 Update copyright
* 70eaf78 Initial import of //depot/www/live/ from the state at revision #head

Ang ating kasaysayan ay magiging linear, katulad ng kunyari tayo ay nag-rebase bago magsumite (na sa katunayan ay ang eksaktong nangyari). Ito ay nangangahulugan na maaari kang libreng lumikha, magtrabaho, magtapon, at mag-merge ng mga branch sa panig ng Git nang walang takot na ang iyong kasaysayan kahit papaano ay magiging hindi magkatugma sa Perforce. Kung maaari mong i-rebase ito, maaari mong i-ambag ito sa isang Perforce na server.

Pag-branch

Kung ang iyong Perforce na proyekto ay may maramihang mga branch, hindi ka malas; ang git-p4 ay maaaring mangasiwa nito sa paraang magmumukha itong katulad ng Git. Sabihin nating ang iyong Perforce na depot ay inilatag katulad nito:

//depot
  └── project
      ├── main
      └── dev

At sabihin nating mayroon kang isang dev na branch, na may isang view spec na nagmumukhang katulad nito:

//depot/project/main/... //depot/project/dev/...

Ang Git-p4 ay maaaring awtomatikong tumuklas ng sitwasyong iyon at gumawa ng nararapat na bagay:

$ git p4 clone --detect-branches //depot/project@all
Importing from //depot/project@all into project
Initialized empty Git repository in /private/tmp/project/.git/
Importing revision 20 (50%)
    Importing new branch project/dev

    Resuming with change 20
Importing revision 22 (100%)
Updated branches: main dev
$ cd project; git log --oneline --all --graph --decorate
* eae77ae (HEAD, p4/master, p4/HEAD, master) main
| * 10d55fb (p4/project/dev) dev
| * a43cfae Populate //depot/project/main/... //depot/project/dev/....
|/
* 2b83451 Project init

Tandaan na ang “@all” na tagatukoy sa depot na landas; iyon ay sinasabihan ang git-p4 na mag-clone ng hindi lang ang pinakabagong changeset para sa subtree na iyon, ngunit ang lahat na mga changeset na nakahawak sa mga landas na iyon. Ito ay mas malapit sa konsepto ng Git ng isang clone, ngunit kung ikaw ay nagtatrabaho sa isang proyekto na may isang mahabang kasaysayan, ito ay maaaring magtagal ng ilang sandali.

Ang --detect-branches na flag ay nagsasabi sa git-p4 na gumamit ng mga branch spec ng Perforce upang magmapa sa mga branch patungo sa Git na mga ref. Kung ang mga pagmapa na ito ay hindi naroroon sa Perforce na server (na isang perpektong balidong paraan sa paggamit ng Perforce), maaari mong sabihan ang git-p4 kung ano ang mga pagmapa ng branch, at makakakuha ka ng parehong resulta:

$ git init project
Initialized empty Git repository in /tmp/project/.git/
$ cd project
$ git config git-p4.branchList main:dev
$ git clone --detect-branches //depot/project@all .

Ang pagtakda ng git-p4.branchList na kumpigurasyon na variable sa main:dev ay sinasabihan ang git-p4 na ang “main” at “dev” ay parehong mga branch, at ang pangalawa ay isang anak ng nauuna.

Kung ngayon tayo ay gagawa ng git checkout -b dev p4/project/dev at gagawa ng ilang mga commit, ang git-p4 ay sapat na matalino upang i-target ang tamang branch kapag tayo ay gumawa ng git p4 submit. Sa kasamaang palad, ang git-p4 ay hind maaaring pagsamahin ang mababaw na mga clone at maramihang mga branch; kung ikaw ay may isang malaking proyekto at gustong magtrabaho sa higit pa sa isang branch, kailangan mong gumawa ng git p4 clone nang isang beses sa bawat branch na gusto mong sumitehan.

Para sa paggawa o pagsasanib ng mga branch, kailangan mong gumamit ng isang Perforce na kliyente. Ang Git-p4 ay maaari lamang mag-sync at magsumite sa umiiral na mga branch, at ito ay maaari lamang gumawa nito nang isang linear na changeset sa bawat pagkakataon. Kung ikaw ay magmi-merge ng dalawang mga branch sa Git at susubukang isumite ang bagong changeset, ang lahat na maitatala ay ang isang bungkos ng mga pagbabago ng file; ang metadata tungkol sa kung anong mga branch ang kasangkot sa pagsasanib ay mawawala.

Buod ng Git at Perforce

Ang Git-p4 ay ginagawang posible ang paggamit ng Git na workflow gamit ang isang Perforce na server, at ito ay medyo magaling nito. Gayunpaman, importanteng tandaan na ang Perforce ay namumuno sa pinagkukunan, at ginagamit mo lang ang Git upang lokal na magtrabaho. Maging talagang maingat lamang tungkol sa pagbabahagi ng Git na mga commit; kung ikaw ay mayroong isang remote na ginagamit ng ibang tao, huwag mag-push ng anumang mga commit na hindi pa nasumite sa Perforce na server.

Kung gusto mong libreng ihalo ang paggamit ng Perforce at Git bilang mga kliyente para sa source control, at maaari mong kumbinsihin ang administrador ng server sa pag-install nito, ang Git Fusion ay ginagawa ang paggamit ng Git na isang primera klaseng version-control na kliyente para sa isang Perforce na server.

Git at TFS

Ang Git ay nagiging popular sa mga developer ng Windows, at kung ikaw ay sumusulat ng code sa Windows, mayroong magandang posibilidad na ikaw ay gumagamit ng Team Foundation Server (TFS) ng Microsoft. Ang TFS ay isang kolaborasyon na suite na naglalaman ng kasiraan at work-item na pagmamasid, proseso na sumusuporta para sa Scrum at iba pa, code review, at kontrol ng bersyon. Mayroong kakaunting kalituhan sa unahan: Ang TFS ay ang server, na sumusuporta sa pagkontrol ng source code gamit ang parehong Git at sarili nitong pasadyang VCS, na tinawag nilang TFVC (Team Foundation Version Control). Ang Git na suporta ay isang medyo bagong tampok para sa TFS (ipinapadala kasama ang 2013 na bersyon), kaya lahat ng mga kasangkapan na nauuna sa iyon na tumutukoy sa bersyon-kontrol na bahagi bilang “TFS”, kahit na sila ay kadalasang nagtatrabaho gamit ang TFVC.

Kung natagpuan mo ang iyong sarili sa isang koponan na gumagamit ng TFVC ngunit gugustuhin mong gumamit ng Git bilang iyong bersyon-kontrol na kliyente, may isang proyekto para sa iyo.

Aling Kasangkapan

Sa katunayan, mayroong dalawa: ang git-tf at git-tfs.

Ang Git-tfs (matatagpuan sa https://github.com/git-tfs/git-tfs) ay isang .NET na proyekto, at (batay sa pagkakasulat nito) ito ay tumatakbo lamang sa Windows. Upang magtrabaho gamit ang mga repositoryo ng Git, ito ay gumagamit ng .NET na mga ugnayan para sa libgit2, isang library-oriented na pagpapatupad ng Git na napakainam sa pagganap at nagpapahintulot ng maraming umaangkop sa bituka ng isang Git na repositoryo. Ang Libgit2 ay hindi isang kompletong pagpapatupad ng Git, kaya upang sakupin ang mga kaibahan ang git-tfs ay talagang tumatawag ng command-line ng Git na kliyente para sa ilang mga operasyon, kaya walang artipisyal na mga hangganan sa kung ano ang maaari nitong gawin sa Git na mga repositoryo. Ang suporta nito sa TFVC na mga tampok ay sobrang gulang, dahil ito ay gumagamit ng Visual Studio na mga pagpupulong para sa mga operasyon sa mga server. Ito ay nangangahulugan na kinakailangan mo ng access sa mga pagpupulong na iyon, na nangangahulugang dapat kang mag-install ng isang kamakailang bersyon ng Visual Studio (anumang edisyon mula sa 2010 na bersyon, na nagsasama ng Express mula sa 2012 na bersyon), o ang Visual Studio na SDK.

Ang Git-tf (na ang tahanan ay nasa https://gittf.codeplex.com) ay isang Java na proyekto, at dahil dito ay tumatakbo sa anumang kompyuter kasama ang isang Java runtime na enviroment. Nag-i-interface ito gamit ang Git na mga repostoryo sa pamamagitan ng JGit (isang JVM na pagpapatupad ng Git), na nangangahulugan na ito ay may birtwal na walang mga limitasyon sa termino ng mga function ng Git. Samantala, ang suporta nito para sa TFVC ay limitado kaysa sa kung ano ang mayroon ng git-tfs – hindi ito sumusuporta ng mga branch, halimbawa.

Kaya bawat kasangkapan ay mayroong mga kalamangan at kahinaan, at mayroong maraming mga sitwasyon na pabor sa isa kaysa sa isa pa. Sasakupin natin ang mga paunang paggamit nitong dalawa sa librong ito.

Kakailanganin mo ng access sa isang TFVC na nakabase na repositoryo upang sumunod sa mga tagubiling ito. Ang mga ito ay hindi kasing dami sa kagubatan kagaya ng Git o Subversion na mga repositoryo, kaya marahil dapat kang gumawa ng isa para sa iyong sarili. Ang Codeplex (https://www.codeplex.com) o Visual Studio Online (http://www.visualstudio.com) ay parehong magandang pagpipilian para rito.

Pagsisimula: git-tf

Ang unang bagay na gagawin mo, katulad ng anumang Git na proyekto, ay mag-clone. Narito ang kung ano ang hitsura katulad ng nasa git-tf:

$ git tf clone https://tfs.codeplex.com:443/tfs/TFS13 $/myproject/Main project_git

Ang unang argumento ay ang URL ng isang TFVC na koleksyon, ang pangalawa ay ang URL nakapormang $/project/branch, at ang pangatlo ay ang landas patungo sa lokal na repositoryo ng Git na lilikhain (ang panghuli ay opsyonal). Ang Git-tf ay maaari lamang magtrabaho sa isang branch sa isang pagkakataon; kung gusto mong gumawa ng isang bagong clone mula sa branch na iyon.

Ito ay gumagawa ng isang buong functional na repositoryo ng Git:

$ cd project_git
$ git log --all --oneline --decorate
512e75a (HEAD, tag: TFS_C35190, origin_tfs/tfs, master) Checkin message

Ito ay tinatawag na isang mababaw na clone, na nangangahulugan na ang napapanahong hanay ng pagbabago lamang ang na-download. Ang TFVC ay hindi nakadesinyo para sa bawat kliyente upang magkaroon ng isang buong kopya ng kasaysayan, kaya ang git-tf na mga default ay kumukuha lamang ng napapanahong bersyon, na higit pang mas mabilis.

Kung mayroon kang ilang oras, marahil ito ay sulit upang i-clone ang buong kasaysayan ng proyekto, gamit ang --deep na opsyon:

$ git tf clone https://tfs.codeplex.com:443/tfs/TFS13 $/myproject/Main \
  project_git --deep
Username: domain\user
Password:
Connecting to TFS...
Cloning $/myproject into /tmp/project_git: 100%, done.
Cloned 4 changesets. Cloned last changeset 35190 as d44b17a
$ cd project_git
$ git log --all --oneline --decorate
d44b17a (HEAD, tag: TFS_C35190, origin_tfs/tfs, master) Goodbye
126aa7b (tag: TFS_C35189)
8f77431 (tag: TFS_C35178) FIRST
0745a25 (tag: TFS_C35177) Created team project folder $/tfvctest via the \
        Team Project Creation Wizard

Pansinin ang mga tag na may mga pangalan katulad ng TFS_C35189; ito ay isang tampok na tumutulong sa iyo upang malaman kung anong Git na mga commit ang nauugnay sa TFVC na mga hanay ng pagbabago. Ito ay isang magandang paraan upang irepresenta ito, dahil maaari mong tingnan gamit ang isang simpleng log na utos kung ano ang iyong mga commit na nauugnay sa isang snapshot na umiiral din sa TFVC. Sila ay hindi na kinakailangan (at sa katunayan maaari mong i-off ang mga ito gamit ang git config git-tf.tag false) – ang git-tf ay pinapanatili ang tunay na commit-changeset na mga pagmapa sa .git/git-tf na file.

Pagsisimula: git-tfs

Ang Git-tfs na pag-clone ay kumikilos ng medyo may kaibahan. Suriin:

PS> git tfs clone --with-branches \
    https://username.visualstudio.com/DefaultCollection \
    $/project/Trunk project_git
Initialized empty Git repository in C:/Users/ben/project_git/.git/
C15 = b75da1aba1ffb359d00e85c52acb261e4586b0c9
C16 = c403405f4989d73a2c3c119e79021cb2104ce44a
Tfs branches found:
- $/tfvc-test/featureA
The name of the local branch will be : featureA
C17 = d202b53f67bde32171d5078968c644e562f1c439
C18 = 44cd729d8df868a8be20438fdeeefb961958b674

Pansinin ang --with-branches na flag. Ang Git-tfs ay may kakayahang sa pagmapa ng TFVC na mga branch patungo sa Git na mga branch, at ang flag na ito ay sinasabihan ito na mag-set up ng isang lokal na Git na branch para sa bawat TFVC na branch. Ito ay labis na inirerekomenda kung ikaw ay kailanmang nag-branch o nag-merge sa TFS, ngunit ito ay hindi gagana sa isang mas lumang server kaysa sa TFS 2010 – bago ang release na iyon, ang “mga branch” ay mga folder lamang, kaya ang git-tfs ay hindi makakapagsabi sa kanila mula sa regular na mga folder.

Tingnan natin ang resulta na repositoryo ng Git:

PS> git log --oneline --graph --decorate --all
* 44cd729 (tfs/featureA, featureA) Goodbye
* d202b53 Branched from $/tfvc-test/Trunk
* c403405 (HEAD, tfs/default, master) Hello
* b75da1a New project
PS> git log -1
commit c403405f4989d73a2c3c119e79021cb2104ce44a
Author: Ben Straub <ben@straub.cc>
Date:   Fri Aug 1 03:41:59 2014 +0000

    Hello

    git-tfs-id: [https://username.visualstudio.com/DefaultCollection]$/myproject/Trunk;C16

May dalawang lokal na mga branch, ang master at featureA, na nagrerepresenta ng paunang panimulang punto ng clone (Trunk sa TFVC) at isang child na branch (featureA sa TFVC). Maaari mo ring makita na ang tfs na “remote” ay mayroon ding pares ng refs: ang default at featureA, na kumakatawan sa TFVC na mga branch. Ang Git-tfs ay magmamapa ng branch na kung saan ka nag-clone patungo sa tfs/default, at ang mga iba pa ay kukuha ng kanilang sariling mga pangalan.

Iba pang bagay na pansinin ay ang git-tfs-id: na mga linya sa commit na mga mensahe. Sa halip na mga tag, ang git-tfs ay gumagamit ng mga marka na ito upang iugnay ang TFVC na mga hanay ng pagbabago sa Git na mga commit. Ito ay may implikasyon na ang iyong Git na mga commit ay magkakaroon ng isang naiibang SHA-1 na hash bago at pagkatapos sila na-push sa TFVC.

Daloy ng trabaho ng Git-tf[s]

Anumang kasangkapan ang iyong ginagamit, dapat kang magtakda ng isang pares ng Git na kompigurasyon na mga halaga upang iwasan ang pagpapatakbo nang may mga isyu.

$ git config set --local core.ignorecase=true
$ git config set --local core.autocrlf=false

Ang halatang susunod na bagay na gugustuhin mong gawin ay ang pagtrabaho sa proyekto. Ang TFVC at TFS ay may iilang mga tampok na maaaring magdagdag ng pagkakumplikado sa iyong daloy ng trabaho:

  1. Ang tampok na mga branch na hindi narepresenta sa TFVC ay nagdaragdag ng kakaunting pagkakumplikado. Ito ay walang kinalaman sa sobrang magkaibang mga paraan na nirerepresenta ng TFVC at Git na mga branch.

  2. Magkaroon ng kamalayan na ang TFVC ay nagpapahintulot sa mga user upang mag-“checkout” ng mga file mula sa server, kinakandado sila upang walang iba na makapag-edit sa kanila. Ito ay halatang hindi ka titigilan sa pag-edit sa kanila sa iyong lokal na repositoryo, ngunit ito ay maaaring maghadlang kapag umabot sa panahon upang mag-push ng iyong mga pagbabago sa TFVC na server.

  3. Ang TFS ay may konsepto na “gated” na mga checkin, kung saan ang isang TFS na build-test cycle ay kailangang matagumpay na kompletuhin bago pahintulutan ang checkin. Ito ay gumagamit ng “shelve” na function sa TFVC, na hindi natin sasakupin nang detalye dito. Maaari mong ipeke ito sa isang manwal na anyo gamit ang git-tf, at ang git-tfs ay nagbibigay ng checkintool na utos na gate-aware.

Sa interes ng kaigsian, ang ating sasakupin dito ay ang masayang landas, na mga sidestep o nag-iiwas ng halos ng mga isyung ito.

Daloy ng trabaho: git-tf

Sabihin nating natapos mo ang ilang trabaho, gumawa ng ilang Git na mga commit sa master, at handa ka nang ibahagi ang iyong pag-unlad sa TFVC na server. Narito ang ating Git na repositoryo:

$ git log --oneline --graph --decorate --all
* 4178a82 (HEAD, master) update code
* 9df2ae3 update readme
* d44b17a (tag: TFS_C35190, origin_tfs/tfs) Goodbye
* 126aa7b (tag: TFS_C35189)
* 8f77431 (tag: TFS_C35178) FIRST
* 0745a25 (tag: TFS_C35177) Created team project folder $/tfvctest via the \
          Team Project Creation Wizard

Gusto nating kumuha ng snapshot na nasa 4178a82 na commit at i-push paitaas ito sa TFVC na server. Unang mga bagay na nauuna: tingnan natin kung anuman sa ating mga kasama sa koponan ay gumawa ng anuman mula nung huli tayong kumonekta:

$ git tf fetch
Username: domain\user
Password:
Connecting to TFS...
Fetching $/myproject at latest changeset: 100%, done.
Downloaded changeset 35320 as commit 8ef06a8. Updated FETCH_HEAD.
$ git log --oneline --graph --decorate --all
* 8ef06a8 (tag: TFS_C35320, origin_tfs/tfs) just some text
| * 4178a82 (HEAD, master) update code
| * 9df2ae3 update readme
|/
* d44b17a (tag: TFS_C35190) Goodbye
* 126aa7b (tag: TFS_C35189)
* 8f77431 (tag: TFS_C35178) FIRST
* 0745a25 (tag: TFS_C35177) Created team project folder $/tfvctest via the \
          Team Project Creation Wizard

Mukhang may ibang nagtatrabaho, rin, at ngayon mayroon na tayong magkakaibang kasaysayan. Ito ay kung saan kumikinang ang Git, ngunit mayroon tayong dalawang pagpipilian kung paano magpatuloy:

  1. Ang paggawa ng isang merge na commit ay nagdaramdam na natural bilang isang user ng Git (kahit na, iyon ay ang kung ano ang ginagawa ng git pull), at ang git-tf ay maaaring gawin ito para sa iyo gamit ang isang simpleng git tf pull. Magbigay alam, gayunpaman, na ang TFVC ay hindi nag-iisip sa ganitong paraan, at kung ikaw ay magpu-push ng merge na mga commit ang iyong kasaysayan ay magsisimulang magmukhang kakaiba sa parehong banda, na maaaring nakakalito. Gayunpaman, kung pinaplano mong magsumite ng lahat ng iyong mga pagbabago bilang isang hanay ng pagbabago, ito na yata ang pinakamadaling mapagpipilian.

  2. Ang pag-rebase ay ginagawang linear ang ating kasaysayan ng commit, na nangangahulugang mayroon tayong opsyon ng pagpapalit sa bawat isa sa ating Git na mga commit sa isang TFVC na hanay ng pagbabago. Dahil iniiwanan nitong bukas ang karamihan sa mga opsyon, inirerekomenda namin na gawin mo ito sa ganitong paraan; ang git-tf ay ginagawang madali ito para sa iyo gamit ang git tf pull --rebase.

Ang pagpili ay nasa iyo. Para sa halimbawang ito, iri-rebase natin ang: For this example, we’ll be rebasing:

$ git rebase FETCH_HEAD
First, rewinding head to replay your work on top of it...
Applying: update readme
Applying: update code
$ git log --oneline --graph --decorate --all
* 5a0e25e (HEAD, master) update code
* 6eb3eb5 update readme
* 8ef06a8 (tag: TFS_C35320, origin_tfs/tfs) just some text
* d44b17a (tag: TFS_C35190) Goodbye
* 126aa7b (tag: TFS_C35189)
* 8f77431 (tag: TFS_C35178) FIRST
* 0745a25 (tag: TFS_C35177) Created team project folder $/tfvctest via the \
          Team Project Creation Wizard

Ngayon handa na tayong gumawa ng isang checkin sa TFVC na server. Ang git-tf ay nagbibigay sa iyo ng pagpipilian sa paggawa ng isang solong hanay ng pagbabago na nagrerepresenta ng lahat ng mga pagbabago mula nung huli (--shallow, na ang default) at gumagawa ng isang panibagong hanay ng pagbabago para sa bawat Git na commit (--deep). Para sa halimbawang ito, gagawa lang tayo ng isang hanay ng pagbabago:

$ git tf checkin -m 'Updating readme and code'
Username: domain\user
Password:
Connecting to TFS...
Checking in to $/myproject: 100%, done.
Checked commit 5a0e25e in as changeset 35348
$ git log --oneline --graph --decorate --all
* 5a0e25e (HEAD, tag: TFS_C35348, origin_tfs/tfs, master) update code
* 6eb3eb5 update readme
* 8ef06a8 (tag: TFS_C35320) just some text
* d44b17a (tag: TFS_C35190) Goodbye
* 126aa7b (tag: TFS_C35189)
* 8f77431 (tag: TFS_C35178) FIRST
* 0745a25 (tag: TFS_C35177) Created team project folder $/tfvctest via the \
          Team Project Creation Wizard

Mayroong isang bagong TFS_C35348 na tag, na nagpapakita na ang TFVC ay nag-iimbak ng eksaktong magkaparehong snapshot sa 5a0e25e na commit. Importanteng tandaan na hindi bawat Git na commit ay nangangailangang magkaroon ng eksaktong kopya sa TFVC; ang 6eb3eb5 na commit, halimbawa, ay hindi umiiral saanman sa server.

Ito ay ang pangunahing daloy ng trabaho. Mayroong iilang ibang konsiderasyon na gugustuhin mong isaisip:

  • Walang nang pag-branch. Ang Git-tf ay maaari lamang gumawa ng mga repositoryo ng Git mula sa isang TFVC na branch sa isang pagkakataon.

  • Pagtulong gamit ang alinman sa TFVC o Git, ngunit hindi ang dalawa. Magkaibang git-tf ay magko-clone ng parehong TFVC na repositoryo ay maaaring magkaroon ng magkaibang commit na SHA-1 na mga hash, na magsasanhi ng walang hanggang sakit sa ulo.

  • Kung ang daloy ng trabaho ng iyong koponan ay naglalaman ng pagtutulungan sa Git at pana-panahong nagsi-sync sa TFVC, upang komunekta lamang sa TFVC kasama ang isa sa mga repositoryo ng Git.

Daloy ng trabaho: git-tfs

Maglakad tayo sa parehong senaryo sa paggamit ng git-tfs. Narito ang bagong mga commit na ginawa natin sa master na branch sa ating Git na repositoryo:

PS> git log --oneline --graph --all --decorate
* c3bd3ae (HEAD, master) update code
* d85e5a2 update readme
| * 44cd729 (tfs/featureA, featureA) Goodbye
| * d202b53 Branched from $/tfvc-test/Trunk
|/
* c403405 (tfs/default) Hello
* b75da1a New project

Ngayon tingnan natin kung may ibang tao na nakagawa ng trabaho habang tayo nagha-hack sa malayo:

PS> git tfs fetch
C19 = aea74a0313de0a391940c999e51c5c15c381d91d
PS> git log --all --oneline --graph --decorate
* aea74a0 (tfs/default) update documentation
| * c3bd3ae (HEAD, master) update code
| * d85e5a2 update readme
|/
| * 44cd729 (tfs/featureA, featureA) Goodbye
| * d202b53 Branched from $/tfvc-test/Trunk
|/
* c403405 Hello
* b75da1a New project

Oo, lumalabas na ang ating kasama sa trabaho ay nagdagdag ng isang bagong TFVC na hanay ng pagbabago, na magpapakita bilang bagong aea74a0 na commit, at ang tfs/default na remote na branch ay lumipat.

Tulad ng git-tf, mayroon tayong dalawang pangunahing mga opsyon para sa kung paano lutasin itong magkakaibang kasaysayan:

  1. Mag-rebase upang mapreserba ang linear na kasaysayan.

  2. Mag-merge upang mapreserba ang kung ano talaga ang nangyari.

Sa kasong ito, tayo ay gagawa ng isang “malalim” na checkin, kung saan ang bawat Git na commit ay magiging isang TFVC na hanay ng pagbabago, kaya gusto nating mag-rebase.

PS> git rebase tfs/default
First, rewinding head to replay your work on top of it...
Applying: update readme
Applying: update code
PS> git log --all --oneline --graph --decorate
* 10a75ac (HEAD, master) update code
* 5cec4ab update readme
* aea74a0 (tfs/default) update documentation
| * 44cd729 (tfs/featureA, featureA) Goodbye
| * d202b53 Branched from $/tfvc-test/Trunk
|/
* c403405 Hello
* b75da1a New project

Ngayon tayo ay handa nang kumpletuhin ang ating pag-ambag sa pamamagitan ng pagtsi-check in ng ating code sa TFVC na server. Gagamitin natin ang rcheckin na utos dito upang lumikha ng isang TFVC na hanay ng pagbabago para sa bawat Git na commit sa landas mula sa HEAD patungo sa unang tfs na remote na branch na natagpuan (ang checkin na utos ay lilikha lamang ng isang hanay ng pagbabago, tulad ng pagpipi ng Git na mga commit).

PS> git tfs rcheckin
Working with tfs remote: default
Fetching changes from TFS to minimize possibility of late conflict...
Starting checkin of 5cec4ab4 'update readme'
 add README.md
C20 = 71a5ddce274c19f8fdc322b4f165d93d89121017
Done with 5cec4ab4b213c354341f66c80cd650ab98dcf1ed, rebasing tail onto new TFS-commit...
Rebase done successfully.
Starting checkin of b1bf0f99 'update code'
 edit .git\tfs\default\workspace\ConsoleApplication1/ConsoleApplication1/Program.cs
C21 = ff04e7c35dfbe6a8f94e782bf5e0031cee8d103b
Done with b1bf0f9977b2d48bad611ed4a03d3738df05ea5d, rebasing tail onto new TFS-commit...
Rebase done successfully.
No more to rcheckin.
PS> git log --all --oneline --graph --decorate
* ff04e7c (HEAD, tfs/default, master) update code
* 71a5ddc update readme
* aea74a0 update documentation
| * 44cd729 (tfs/featureA, featureA) Goodbye
| * d202b53 Branched from $/tfvc-test/Trunk
|/
* c403405 Hello
* b75da1a New project

Pansinin kung paano pagkatapos ng bawat matagumpay na checkin sa TFVC na server, ang git-tfs ay nagre-rebase ng natitirang trabaho sa kung ano ang ginawa nito. Iyon ay dahil nagdaragdag ito ng git-tfs-id na field sa ilalim ng commit na mga mensahe, na nagbabago sa SHA-1 na mga hash. Ito ay eksaktong batay sa pagkakadisenyo, at walang dapat ipangamba, ngunit dapat mong bigyang alam na ito ay nangayayri, lalo na kung ikaw ay namamahagi ng mga Git na commit sa iba.

Ang TFS ay may maraming mga tampok na sumasama sa sistema na version control nito, katulad ng mga item ng trabaho, itinalagang mga taga-review, naka-gate na mga checkin, at iba pa. Maaaring masalimuot na magtrabaho sa mga tampok na ito gamit lamang ang isang command-line na kasangkapan, ngunit sa kabutihang palad ang git-tfs ay hahayaan kang maglunsad ng isang grapikal na checkin na kasangkapan nang sobrang dali:

PS> git tfs checkintool
PS> git tfs ct

Nagmumukha itong medyo ganito:

The git-tfs checkin tool.
Figure 148. The git-tfs checkin tool.

Ito ay magmumukhang pamilyar sa mga gumagamit ng TFS, dahil ito ay magkapareho ng diyalogo sa nailunsad mula sa loob ng Visual Studio.

Ang Git-tfs din ay hahayaang kang mag-kontrol ng TFVC na mga branch mula sa iyong Git na repositoryo. Bilang isang halimbawa, gumawa tayo ng isa:

PS> git tfs branch $/tfvc-test/featureBee
The name of the local branch will be : featureBee
C26 = 1d54865c397608c004a2cadce7296f5edc22a7e5
PS> git log --oneline --graph --decorate --all
* 1d54865 (tfs/featureBee) Creation branch $/myproject/featureBee
* ff04e7c (HEAD, tfs/default, master) update code
* 71a5ddc update readme
* aea74a0 update documentation
| * 44cd729 (tfs/featureA, featureA) Goodbye
| * d202b53 Branched from $/tfvc-test/Trunk
|/
* c403405 Hello
* b75da1a New project

Ang paggawa ng isang branch sa TFVC ay nangangahulungan sa pagdaragdag ng isang hanay ng pagbabago kung saan ang branch na iyon ay umiiral na ngayon, at ito ay nakapanukala bilang isang Git na commmit. Tandaan din na ang git-tfs ay gumawa ng tfs/featureBee na remote na branch, ngunit ang HEAD ay nakaturo pa rin sa master. Kung gusto mong magtrabaho sa preskong pagkakagawa na branch, gugustuhin mong magbase ng iyong bagong mga commit sa 1d54865 na commit, marahil sa pamamagitan ng paggawa ng isang paksa na branch mula sa commit na iyon.

Git at TFS na Buod

Ang Git-tf at Git-tfs ay parehong dakilang mga kasangkapan para sa pag-interface na may isang TFVC na server. Pinapayagan ka nilang lokal na gamitin ang kapangyarihan ng Git, umiwas sa patuloy na pagkakaroon ng papunta at pabalik sa sentral na TFVC na server, at gawing sobrang mas madali ang iyong buhay bilang isang developer, na hindi pinipilit ang iyong buong koponan na lumipat sa Git. Kung ikaw ay nagtatrabaho sa Windows (na pwede kung ang iyong koponan ay gumagamit ng TFS), marahil gugustuhin mong gumamit ng git-tfs, dahil ang hanay tampok nito ay mas kumpleto, ngunit kung ikaw ay nagtatrabaho sa ibang plataporma, gagamitin mo ang git-tf, na mas limitado. Sa kadalasang mga kasangkapan sa kabanatang ito, dapat kang pumili ng isa sa mga sistema ng version-control na ito upang maging makanoniko, at gamitin ang iba pang isa na nasa isang pantulong na anyo – alinman sa Git o TFVC ang dapat maging sentro ng kolaborasyon, hindi ang dalawa.