Git
Chapters ▾ 2nd Edition

7.13 Git Алатки - Заменување

Заменување

Како што веќе нагласивме, објектите во објектната база на податоци на Git се непроменливи, но Git обезбедува интересен начин да pretend да ги замени објектите во својата база на податоци со други објекти.

Командата replace ви овозможува да наведете објект во Git и да кажете" секој пат кога ќе се повикате на this објект, да се преправате дека е different објект ". Ова е најчесто корисно за замена на една обврска во историјата со друга, без да мора да ја обнови целата историја со, на пример, git filter-branch.

На пример, да речеме дека имате голема историја на код и сакате да го поделите вашето складиште во една кратка историја за нови програмери и една многу подолга и поголема историја за луѓето заинтересирани за рударство. Можете да префрлите една историја врз друга со "замена" на најстариот залог во новата линија со најновиот залог за постариот. Ова е убаво, бидејќи тоа значи дека всушност не морате да ја преработите секоја заложба во новата историја, како што обично треба да направите за да ги споите заедно (бидејќи родителството влијае на SHA-1s).

Ајде да го пробаме ова. Да земеме постоечко складиште, да го поделиме во две складишта, еден неодамнешен и еден историски, а потоа ќе видиме како можеме да ги рекомбинираме без да ги смениме неодамнешните складишта SHA-1 вредности преку replace.

Ќе користиме едноставно складиште со пет едноставни обврски:

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

Ние сакаме да го разделиме ова во две линии на историјата. Една линија оди од изврши еден да изврши четири - тоа ќе биде историски. Втората линија само ќе се изврши четири и пет - тоа ќе биде неодамнешната историја.

replace1

Па, креирањето на историската историја е лесно, можеме само да ставиме филијала во историјата, а потоа да ја притиснеме таа гранка до главната гранка на ново оддалечено складиште.

$ 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

Сега можеме да извршиме притисок врз новата гранка "историја" во "господарната" гранка на нашето ново складиште:

$ 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

Добро, па нашата историја е објавена. Сега потешките делови ја намалуваат нашата понова историја, па затоа е помала. Потребно е преклопување за да можеме да го замениме извршувањето во една со еквивалентно извршување во другата, па затоа ќе го скратиме ова за да правиме само четири и пет (па извршиме четири преклопувања).

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

Корисно е во овој случај да се создаде основен обврзник кој има инструкции за проширување на историјата, па затоа други развивачи знаат што да прават ако го погодат првото извршување во скратената историја и им треба повеќе. Значи, она што ќе го направиме е да создадеме првичен објект за извршување како наша основна точка со инструкции, а потоа да ги ребритираме останатите обврски (четири и пет) на врвот од неа.

За да го сториме тоа, треба да избереме точка за да се поделиме, што за нас е третата обврска, која е 9c68fdc во SHA-говорот. Значи, нашата основа ќе се заснова на тоа дрво. Ние можеме да ја создадеме основната обврска користејќи ја командата commit-tree, која зазема само едно дрво и ќе ни даде сосема нов објект за SHA-1 без родители.

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

Командата commit-tree е една од множествата на команди кои вообичаено се нарекуваат команди за" водовод ". Ова се команди кои обично не се наменети за директно користење, туку се користат од * други * Git команди за да прават помали работни задачи. Во прилики кога правиме вакви работи, тие ни овозможуваат да правиме навистина ниско ниво на работи, но не се наменети за секојдневна употреба. Можете да прочитате повеќе за команди за водовод во << _plumbing_porcelain >>

replace3

Добро, па сега кога имаме основен залог, можеме да ја оспориме остатокот од нашата историја на врвот на тоа со git rebase -onto. Аргументот --onto ќе биде SHA-1 што се вративме од` commit-tree`, а точка на rebase ќе биде третата обврска (родителот на првата обврска која сакаме да ја зачуваме, 9c68fdc):

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

Добро, па сега повторно ја напишавме нашата понова историја на врвот на фрлање база обврски што сега има инструкции во него за тоа како да се реконструира целата историја ако сакаме да. Ние можеме да ја поттикнеме таа нова историја во нов проект, а сега кога луѓето ќе клонираат тоа складиште, ќе ги видат само најновите две обврски, а потоа базата ќе извршат со инструкции.

Ајде сега да ги префрлиме улогите на некој кој го клонира проектот за прв пат кој сака целата историја. За да ги добиете податоците од историјата по клонирањето на ова скратено складиште, ќе треба да додадете втор далечински управувач за историското складиште и да донесам:

$ 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

Сега соработникот ќе ги има своите неодамнешни обврски во гранката "господар" и историчарот се обврзува во гранката "проект-историја / господар".

$ 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

За да ги комбинирате, едноставно можете да го повикате git replace со обврската што сакате да ја замените, а потоа и за извршувањето со кое сакате да го замените. Затоа сакаме да го замениме "четвртото" извршување во главната гранка со "четврто" извршување во гранката "проект-историја / господар":

$ git replace 81a708d c6e1e95

Сега, ако погледнете во историјата на master филијалата, се чини дека изгледа вака:

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

Кул, нели? Без да мораме да ги промениме сите SHA-1 наспроти низводно, можевме да замениме една обврска во нашата историја со сосема поинаква заложба и сите нормални алатки (bisect,` blame`, итн.) Ќе работат како би очекувале тие да .

replace5

Интересно е што сè уште покажува 81a708d како SHA-1, иако всушност ги користи податоците за commit` c6e1e95` со кои сме го замениле. Дури и ако извршите команда како cat-file, таа ќе ви ги прикаже заменетите податоци:

$ 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

Запомнете дека вистинскиот родител на 81a708d беше нашиот залог на место (` 622e88e`), а не 9c68fdce, како што е наведено тука.

Друга интересна работа е што овие податоци се чуваат во нашите референци:

$ 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

Ова значи дека е лесно да ја споделиме нашата замена со други, бидејќи можеме да го притиснеме ова на нашиот сервер, а другите луѓе лесно може да го преземат. Ова не е толку корисно во сценариото за пресадување на историјата што ние го поминавме овде (бидејќи секој ќе ги презема двете истории во секој случај, па зошто да ги одвои?), Но може да биде корисно и во други околности.