Git
Chapters ▾ 2nd Edition

7.13 Git Alətləri - Dəyişdirmək

Dəyişdirmək

Daha əvvəl vurğuladığımız kimi, Git-in obyektlər bazasındakı obyektlər dəyişilməzdir, lakin Git verilənlər bazasında olan obyektləri digər obyektlərlə əvəz etmək üçün maraqlı bir yol təqdim edir.

replace əmri Git-də bir obyekti göstərməyə və "hər dəfə this obyektə istinad etdikdə, onu fərqli_ obyekt" kimi göstərməyə imkan verir. Bu, ümumiyyətlə git filter-branch ilə bütün tarixi yenidən qurmadan, tarixinizdəki bir commit-i digəri ilə əvəz etmək üçün çox faydalıdır.

Məsələn, deyək ki, böyü bir kod tarixiniz var və depolarınızı yeni developerlər üçün qısa bir tarixə və məlumat hasilatı ilə maraqlanan insanlar üçün daha uzun və daha böyük bir tarixə bölmək istəyirsiniz. Yeni sətrdəki ən köhnə commit-i, köhnə olanın ən son commit-i ilə "replacing" etməklə bağlaya bilərsiniz Bu gözəldir, çünki adətən onları birləşdirmək üçün etməli olduğunuz kimi (çünki valideynlik SHA-1-lərə təsir göstərir) yeni tarixdəki hər bir commit-i yenidən yazmaq məcburiyyətində olmadığınız anlamına gəlir.

Bunu sınayaq. Mövcud bir deponu götürək, onu biri yeni digəri keçmiş olmaq üzrə iki depoya ayırın və sonra son depoların SHA-1 dəyərlərini replace yolu ilə dəyişdirmədən onları necə birləşdirəcəyimizi görəcəyik.

Biz beş sadə commit ilə sadə bir depo istifadə edək:

$ git log --oneline
ef989d8 Fifth commit
c6e1e95 Fourth commit
9c68fdc Third commit
945704c Second commit
c1822cf First commit

Bunu tarixin iki xəttinə bölmək istəyirik. Birinci sətrdə commit-lər birdən dördə qədər dəvam edəcək - bu tarixi bir xətt olacaqdır. İkinci sətr sadəcə dörd və beşinci commit-lərdən ibarət olacaq - bu yaxın tarix olacaq.

replace1

Yaxşı, tarixi bir tarix yaratmaq asandır, sadəcə tarixə bir branch əlavə edə bilərik və sonra bu branch-ı yeni uzaq bir deponun master branch-na push edə bilərik.

$ 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

İndi yeni history branch-ını yeni depomuzun master branch-na push edə bilərik:

$ 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, buna görə tariximiz dərc olunur. İndi daha çətin hissə yaxın tariximizi qısaldıb, balacalaşdırmaqdır. Birində olan bir commiti digərində olan ekvivalent bir commit ilə əvəz edə biləcəyimiz üçün üst-üstə düşməyimiz lazımdır, buna görə dörd və beş commit-i yerinə yetirmək üçün (dörd üst-üstə düşmək üçün) kəsilmək fikrindəyik.

$ git log --oneline --decorate
ef989d8 (HEAD, master) Fifth commit
c6e1e95 (history) Fourth commit
9c68fdc Third commit
945704c Second commit
c1822cf First commit

Bu vəziyyətdə tarixin genişləndirilməsi barədə təlimatları olan baza commit-i yaratmaq faydalıdır, buna görə digər developerlər kəsilmiş tarixdə ilk commit-i vurduqda və daha çoxuna ehtiyac duyduqda nə edəcəyini bilirlər. Beləliklə, edəcəyimiz şey təlimatla təməl nöqtəmiz kimi ilkin commit-i obyekti yaratmaq, sonra qalan əmrləri (dörd və beş) yenidən əvəz etməkdir.

Bunu etmək üçün, bölüşmək üçün bir nöqtə seçməliyik ki, bu da bizim üçüncü commit-mizdir, yəni SHA-speak-də 9c68fdc-dir. Beləliklə, baza commit-imiz həmin ağacdan asılı olacaq. Əsas commit-mizi commit-tree əmrindən istifadə edərək yarada bilərik, bu sadəcə bir ağac alır və bizə yeni, valideynsiz bir commit obyekti SHA-1-i verir.

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

commit-tree əmri, ümumiyyətlə plumbing əmrləri adlandırılan bir sıra əmrlərdən biridir. Bunlar ümumiyyətlə birbaşa istifadə üçün nəzərdə tutulmayan əmrlərdir, əksinə daha kiçik işləri görmək üçün başqa Git əmrləri tərəfindən istifadə olunur. Bu kimi səliqəli şeylər etdiyimiz hallarda bizə həqiqətən aşağı səviyyəli işlər görməyə imkan verir, lakin gündəlik istifadə üçün nəzərdə tutulmur. Santexnika əmrləri haqqında daha çox məlumatı Plumbing və Porcelain-dən oxuya bilərsiniz.

replace3

OK, buna görə bir əsas commit-miz olduğuna görə tariximizin qalan hissəsini git rebase --onto ilə əvəz edə bilərik. --onto argumenti,commit-tree-dan geri aldığımız SHA-1 olacaq və yenidən yerinə yetirmə nöqtəsi üçüncü commit olacaqdır (saxlamaq istədiyimiz ilk ommit-in valideyni, 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, buna görə yaxın keçmişimizi atmaqdan çəkinən əsas commit-ə yazmaq istədikdə bütün tarixi yenidən yaratmağımız barədə təlimatları yazdıq. Bu yeni tarixi yeni bir layihəyə köçürə bilərik və indi insanlar bu deponu klonladıqda, göstərişlərlə əsas commit-in ardınca son iki commit-i görəcəklər.

İndi bütün rolları ilk dəfə layihəni klonlayan birinə dəyişdirək. Bu kəsilmiş depo klonlaşdırıldıqdan sonra tarix məlumatlarını əldə etmək üçün, tarixi depo üçün ikinci bir məsafəni əlavə etmək lazımdır.

$ 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

İndi işçi master branch-ındakı son vəzifələrini və project-history/master branch-ında tarixi commit-ləri yerinə yetirəcəkdir.

$ 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

Bunları birləşdirmək üçün əvəz etmək istədiyiniz commit-i ilə sadəcə git replace çağıra bilərsiniz. Beləliklə, master branch-ındakı "fourth" commit-i project-history/master branch-ındakı "fourth" commit-i ilə əvəz etmək istəyirik:

$ git replace 81a708d c6e1e95

İndi master branch-nın tarixinə baxsanız, belə görünür:

$ git log --oneline master
e146b5f Fifth commit
81a708d Fourth commit
9c68fdc Third commit
945704c Second commit
c1822cf First commit

Əladır, elə deyil? Bütün SHA-1-ləri yuxarıdan dəyişdirmədən, tariximizdəki bir commiti tamamilə fərqli bir commit ilə əvəz edə bildik və bütün normal vasitələr (bisect, blame və s.) onlardan gözlədiyimiz şəkildə işləyəcək.

replace5

Maraqlısı odur ki, əvəz etdiyimiz c6e1e95 commit məlumatlarından istifadə etməsinə baxmayaraq, hələ də 81a708d-ni SHA-1 olaraq göstərir. cat-file kimi bir əmr işləsəniz də əvəz edilmiş məlumatları göstərəcəkdir:

$ 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-in həqiqi valideyni, burada qeyd edildiyi kimi 9c68fdce deyil, əvəzedicimiz (622e88e) olduğunu unutmayın ki.

Başqa bir maraqlı məqam bu məlumatların istinadlarımızda saxlanmasıdır:

$ 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

Bu o deməkdir ki, dəyişdirəcəyimizi başqaları ilə bölüşmək asandır, çünki bunu serverimizə push edə bilərik və digər insanlar asanlıqla yükləyə bilər. Bu keçdiyimiz tarixin paylanması ssenarisində o qədər də faydalı deyil (çünki hər kəs hər iki tarix də yükləyəcək, buna görə niyə onları ayırasız ki?), lakin digər hallarda faydalı ola bilər.