Git
Chapters ▾ 2nd Edition

7.13 Mga Git na Kasangkapan - Pagpapalit

Pagpapalit

Tulad ng aming binigyan diin noon, ang mga bagay sa Git na bagay na database na hindi nagbabago, ngunit ang ay nagbibigay ng interesadong paraan upang magpanggap para magpalit ng mga bagay sa kanyang database na may ibang mga bagay.

Ang replace na utos ay hinahayaan kang tumukoy ng isang bagay sa Git at sabihin mo "sa tuwing tinutikoy mo itong bagay, ay nagpapanggap na ito ay ibang bagay". Ito ay pinaka-karaniwang kapaki-pakinabang para sa pagpalit ng isang commit sa iyong kasaysayan na sa isa pang walang muling maitayo sa buong kasaysayan na may, sinasabi mong, git filter-branch.

Halimbawa, sabihin natin na meron kang isang malaking code sa iyong kasaysayan at gusto mong hatiin ang iyong repositoryo sa isang maikling kasaysayan para sa bagong mga developer at isang mas matagal at mataas na kasaysayan para sa taong interesado sa pagmimina ng datos. Maaari mong i-graft ang isang kasaysayan na papunta sa iba sa pamamagitan ng "pagpapalit" sa pinakamaagang commit sa bagong linya na may pinakabagong commit sa mas matanda. Ito ay maganda dahil ang ibig sabihin nito ay wala ka talagang na sulat muli sa bawat commit sa bagong kasaysayan, gaya ng gusto mo na normal na meron kang gagawin upang makasali sa kanila na magkasama (dahil ang porsyento ay nakakaapekto sa SHA-1s).

Subukan nati ito. Kumuha tayo ng isang umiiral na repositoryo, hatiin ito sa dalawang repositoryo, isa sa pinakabago at isa sa makasaysayan, at pagkatapos tingnan natin kung papaano natin ma mapagsama sila sa pagbabago sa pinakabagong repositoryo na SHA-1 na mga halaga sa pamamagitan ng replace.

Gagamitan namin ng isang simpleng repositoryo na may limang simpleng mga commit:

$ git log --oneline
ef989d8 fifth commit
c6e1e95 fourth commit
9c68fdc third commit
945704c second commit
c1822cf first commit

Gusto naming masira ito sa dalawang linya ng kasaysayan. Isang linya papunta mula sa commit na isa hanggang sa commit na apat - at iyon ang magiging kasaysayan. Ang pangalawang linya ay magiging mga commit na apat at lima - iyon ay magiging kamakailang kasaysayan.

replace1

Kahit, ang paglikha ng makasaysayang kasaysayan ay madali, maaari lang nating lagyan ng branch sa kasaysayan at pagkatapos i-push ang branch na iyon sa master na branch sa isang bagong malayong repositoryo.

$ git branch history c6e1e95
$ git log --oneline --decorate
ef989d8 (HEAD, master) fifth commit
c6e1e95 (history) fourth commit
9c68fdc third commit
945704c second commit
c1822cf first commit
replace2

Ngayon maaari na tayong mag-push sa bagong history na branch sa master na branch sa ating bagong repositoryo:

$ git remote add project-history https://github.com/schacon/project-history
$ git push project-history history:master
Counting objects: 12, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (12/12), 907 bytes, done.
Total 12 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (12/12), done.
To git@github.com:schacon/project-history.git
 * [new branch]      history -> master

OK, kaya ang ating kasaysayan ay i-publish. Ngayon ang mas mahirap na parte ay ang pagbawas sa ating pinakabagong kasaysayan na pababa kaya maliit ito. Kailagan natin ng isang pagsasapaw para tayo ay makapagpalit ng isang commit sa isa na may katumbas na commit sa iba, kaya pupunta tayo sa pagbawas nito sa mga na commit lamang na apat at lima (kayta ang commit na apat na mga pagsasapaw).

$ git log --oneline --decorate
ef989d8 (HEAD, master) fifth commit
c6e1e95 (history) fourth commit
9c68fdc third commit
945704c second commit
c1822cf first commit

Ito ay kapaki-pakinabang sa kasong ito upang lumikha ng base na commit na mayroong mga pagtuturo kung paano palawakin ang kasaysayan, kaya ang ibang developer at malaman kung ano ang gagawin kung sila ay unang pumindot sa nabawas na kasaysayan at kailangan pa. Kaya, kung ano ang gagawin natin ay ang paglikha ng pasiunang commit na bagay bilang ating base na punto na may mga pagtuturo, pagkatapos ang rebase sa natitirang mga commit (apat at lima) sa itaas nito.

Upang gawin iyon, kailangan natin pumili ng isang punto para hatiin sa, na para sa amin ay ang pangatlong commit, na kung saan ay 9c68fdc sa SHA-speak. Kaya, sa aming base commit ay magiging batay sa tree na iyon. Maaari tayong lumikha ng ating base commit gamit ang commit-tree na utos, na kung saan ay kumukuha ng isang tree at nagbigay sa atin na isang napakabagong, walang magulang na commit na bagay na SHA-1 sa likod.

$ echo 'get history from blah blah blah' | git commit-tree 9c68fdc^{tree}
622e88e9cbfbacfb75b5279245b9fb38dfea10cf

Ang commit-tree na utos ay isa sa isang set ng mga utos na karaniwang tinutukoy bilang plumbing na mga utos. Ang mga utos na ito ay hindi sa pangkalahatang para sa gumagamit nang diretso, ngunit sa halip ay ginagamit ng ibang mga utos ng Git na gumawa ng maliliit na mga trabaho. Sa mga okasyon kapag kami ay gumawa ng kakaiba mga bagay na tulad nito, pinapahintulotan tayo na gumawa ng mababang antas ngunit hindi nakalaan para sa pang-araw-araw na paggamit. You can read more about plumbing commands in Plumbing and Porcelain

image::images/replace3.png

OK, kaya ngayon meron na kaming isang base na commit, maaari naming i-rebase ang lahat sa ating kasaysayan na sa itaas na may git rebase --onto. Ang --onto na argumento ay ang SHA-1 nakabalik lang kami mula sa commit-tree at ang rebase na punto ay magiging pangatlong commit (ang magulang sa unang commit ay gusto naming panatalihin,9c68fdc)

$ git rebase --onto 622e88 9c68fdc
First, rewinding head to replay your work on top of it...
Applying: fourth commit
Applying: fifth commit
replace4

OK, kaya ngayon nagsusulat uli kami sa aming kamakailan lang na kasaysayan sa itaas ng isang itinapon na base commit na mayroon na ngayong mga tagubilin sa loob at kung papano i-reconstitute ang buong kasaysayan kung gusto nila. Maaari nalang i-push ang bagong kasaysayan sa isang bagong proyekto at ngayon kapag ang tao ay nag-clone sa repositoryo na iyon, makikita nila ang pinakabagong dalawang commit at pagkatapos isang base commit na may mga pagtuturo.

Lumipat tayo ngayon ng mga papel para sa isang tao na mag-clone sa proyekto para sa unang pagkakataon kung sino ang may gusto sa buong kasaysayan. Para makakuha ng kasaysayan ng datos pagkatapos na mai-clone ito sa naka-truncate na repositoryo, magkakaroon ng isa upang madagdag ang pangalawang remote para sa makasaysayang repositoryo at kunin:

$ git clone https://github.com/schacon/project
$ cd project

$ git log --oneline master
e146b5f fifth commit
81a708d fourth commit
622e88e get history from blah blah blah

$ git remote add project-history https://github.com/schacon/project-history
$ git fetch project-history
From https://github.com/schacon/project-history
 * [new branch]      master     -> project-history/master

Ngayon ang tagatulong ay magkakaroon ng kanilang kamakailan na mga commit sa master na branch at ang makasaysayang mga commit sa project-history/master na branch.

$ git log --oneline master
e146b5f fifth commit
81a708d fourth commit
622e88e get history from blah blah blah

$ git log --oneline project-history/master
c6e1e95 fourth commit
9c68fdc third commit
945704c second commit
c1822cf first commit

Upang pagsamahin ang mga ito, maaari mong tawagan lang ang git replace na may commit na gusto mong ipalit at pagkatapos ang commit na gusto mong palitan ito sa. Kaya gusto naming palitan ang "fourth" na commit sa master na branch na may "fourth" na commit sa project-history/master na branch:

$ git replace 81a708d c6e1e95

Ngayon, kung titingnan natin ang kasaysayan sa master na branch, lilitaw na ganito ang hitsura:

$ git log --oneline master
e146b5f fifth commit
81a708d fourth commit
9c68fdc third commit
945704c second commit
c1822cf first commit

Cool, tama? Nang walang pagbabago sa lahat sa SHA-1s na upstream, nagawa naming palitan ang isang commit sa aming kasaysayan na may isang ganap na naiiba na commit at lahat ng mga normal na kasangkapan (bisect, blame, etc) gagana kung paano namin inaasahan ang mga ito.

replace5

Kapansin-pansin, ito ay nagpapakita ng 81a708d bilang ang SHA-1, kahit na ito talaga ang gumagamit ng c6e1e95 na commit na datos na pinalit namin ito. Kahit na ikaw ay nagpatakbo ng isang utos tulad ng cat-file, ito ay nagpapakita sa iyo sa napalitan na datos:

$ git cat-file -p 81a708d
tree 7bc544cf438903b65ca9104a1e30345eee6c083d
parent 9c68fdceee073230f19ebb8b5e7fc71b479c0252
author Scott Chacon <schacon@gmail.com> 1268712581 -0700
committer Scott Chacon <schacon@gmail.com> 1268712581 -0700

fourth commit

Tandaan na ang aktwal na magulang sa 81a708d ay ang aming placeholder na commit (622e88e), hindi 9c68fdce gaya ng sinasabi nito dito.

Isa pang kawili-wili na bagay na ang datos na ito ay tinago sa aming mga reperensiya:

$ git for-each-ref
e146b5f14e79d4935160c0e83fb9ebe526b8da0d commit	refs/heads/master
c6e1e95051d41771a649f3145423f8809d1a74d4 commit	refs/remotes/history/master
e146b5f14e79d4935160c0e83fb9ebe526b8da0d commit	refs/remotes/origin/HEAD
e146b5f14e79d4935160c0e83fb9ebe526b8da0d commit	refs/remotes/origin/master
c6e1e95051d41771a649f3145423f8809d1a74d4 commit	refs/replace/81a708dd0e167a3f691541c7a6463343bc457040

Ito ay nangangahulugan na ito ay madali lang ibahagi ang aming kapalit sa iba, dahil maaari nating i-push ito sa ating sever at ang ibang tao ay madaling maka-download nito. Ito ay hindi nakakatulong sa kasaysayan ng paghugpong na sitwasyon na kami ay nawala rito (dahil ang lahat ay maaaring maging mag-download sa parehong mga kasaysayan sa papaano mang paraan, kaya bakit paghiwalayin ang mga ito?) ngunit maaari itong maging kapaki-pakinabang sa ibang mga pangyayari.