-
1. Başlanğıc
- 1.1 Versiyaya Nəzarət Haqqında
- 1.2 Git’in Qısa Hekayəsi
- 1.3 Git Nədir?
- 1.4 Əmr Sətiri
- 1.5 Git’i Quraşdırmaq
- 1.6 İlk Dəfə Git Quraşdırması
- 1.7 Kömək Almaq
- 1.8 Qısa Məzmun
-
2. Git’in Əsasları
-
3. Git’də Branch
- 3.1 Nutshell’də Branch’lar
- 3.2 Sadə Branching və Birləşdirmə
- 3.3 Branch İdarəedilməsi
- 3.4 Branching İş Axınları
- 3.5 Uzaq Branch’lar
- 3.6 Rebasing
- 3.7 Qısa Məzmun
-
4. Server’də Git
- 4.1 Protokollar
- 4.2 Serverdə Git Əldə Etmək
- 4.3 Sizin öz SSH Public Key’nizi yaratmaq
- 4.4 Server qurmaq
- 4.5 Git Daemon
- 4.6 Smart HTTP
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 Üçüncü Tərəf Seçimləri
- 4.10 Qısa Məzmun
-
5. Paylanmış Git
-
6. GitHub
-
7. Git Alətləri
- 7.1 Reviziya Seçimi
- 7.2 Interaktiv Səhnələşdirmə
- 7.3 Stashing və Təmizləmə
- 7.4 İşinizin İmzalanması
- 7.5 Axtarış
- 7.6 Tarixi Yenidən Yazmaq
- 7.7 Reset Demystified
- 7.8 İnkişaf etmiş Birləşmə
- 7.9 Rerere
- 7.10 Git ilə Debugging
- 7.11 Alt Modullar
- 7.12 Bundling
- 7.13 Dəyişdirmək
- 7.14 Etibarlı Yaddaş
- 7.15 Qısa Məzmun
-
8. Git’i Fərdiləşdirmək
- 8.1 Git Konfiqurasiyası
- 8.2 Git Atributları
- 8.3 Git Hook’ları
- 8.4 Git-Enforced Siyasət Nümunəsi
- 8.5 Qısa Məzmun
-
9. Git və Digər Sistemlər
- 9.1 Git Müştəri kimi
- 9.2 Git’ə Miqrasiya
- 9.3 Qısa Məzmun
-
10. Git’in Daxili İşləri
- 10.1 Plumbing və Porcelain
- 10.2 Git Obyektləri
- 10.3 Git Referansları
- 10.4 Packfile’lar
- 10.5 Refspec
- 10.6 Transfer Protokolları
- 10.7 Maintenance və Məlumatların Bərpası
- 10.8 Mühit Dəyişənləri
- 10.9 Qısa Məzmun
-
A1. Appendix A: Digər Mühitlərdə Git
- A1.1 Qrafik interfeyslər
- A1.2 Visual Studio’da Git
- A1.3 Visual Studio Code’da Git
- A1.4 Eclipse’də Git
- A1.5 Sublime Text’də Git
- A1.6 Bash’da Git
- A1.7 Zsh’də Git
- A1.8 PowerShell’də Git
- A1.9 Qısa Məzmun
-
A2. Appendix B: Proqramlara Git Daxil Etmək
- A2.1 Əmr-sətri Git
- A2.2 Libgit2
- A2.3 JGit
- A2.4 go-git
- A2.5 Dulwich
-
A3. Appendix C: Git Əmrləri
- A3.1 Quraşdırma və Konfiqurasiya
- A3.2 Layihələrin Alınması və Yaradılması
- A3.3 Sadə Snapshotting
- A3.4 Branching və Birləşmə
- A3.5 Layihələrin Paylaşılması və Yenilənməsi
- A3.6 Yoxlama və Müqayisə
- A3.7 Debugging
- A3.8 Patching
- A3.9 E-poçt
- A3.10 Xarici Sistemlər
- A3.11 İdarəetmə
- A3.12 Plumbing Əmrləri
7.8 Git Alətləri - İnkişaf etmiş Birləşmə
İnkişaf etmiş Birləşmə
Git-də birləşdirmə əsasən olduqca asandır. Git başqa bir branch-ı dəfələrlə birləşdirməyi asanlaşdırdığından, uzunmüddətli bir branch-a sahib ola biləcəyinizi ifadə edir, ancaq irəlilədiyiniz müddətdə onu saxlaya bilərsiniz, yəni, çox böyük bir konfliktə təəccüblənməkdənsə kiçik münaqişələri tez-tez həll etməklə, seriyanında sonunda böyük problemlərdən yan keçə bilərsiniz.
Ancaq bəzən çətin konfliktlər əmələ gəlir. Bəzi digər versiyalara nəzarət sistemlərindən fərqli olaraq, Git münaqişələrin həlli məsələsində həddən artıq ağıllı olmağa çalışmır. Git-in fəlsəfəsi birləşmə həllinin nə vaxt olacağını müəyyənləşdirməkdə ağıllı olmaqdır, ancaq konflikt varsa, avtomatik olaraq həll etmək üçün ağıllı olmağa çalışmır. Buna görə də, tez ayrılan iki branch-ı birləşdirmək üçün çox gözləsəniz, bəzi problemlərlə qarşılaşa bilərsiniz.
Bu hissədə bəzi problemlərin nədən ibarət olacağını və Git-in bu daha çətin vəziyyətləri həll etmək üçün sizə hansı vasitələri verdiyini nəzərdən keçirəcəyik. Ayrıca edə biləcəyiniz fərqli, qeyri-standart birləşmələrin bəzilərini də əhatə edəcəyik, həm də etdiyiniz birləşmələri necə geri çəkə biləcəyimizə baxacağıq.
Konfliktləri Birləşdirmə
Daha mürəkkəb konfliktlər üçün Əsas Birləşmə Konfiliktləri-də birləşmə konfliktlərinin həlli ilə bağlı bəzi əsasları izah etsək də, Git nəyin baş verdiyini və münaqişəni daha yaxşı necə həll edəcəyinizi anlamağa kömək edəcək bir neçə vasitə təqdim edir.
Əvvəlcə, əgər mümkündürsə, konfliktlər ola biləcək birləşməni etməzdən əvvəl işçi qovluğunun təmiz olduğundan əmin olun. İşiniz davam edirsə, ya müvəqqəti bir branch-a verin və ya zibilə atın. Bu, burada etdiyiniz hər şeyi geri qaytara biləcəyiniz üçün edir. Birləşdirməyə çalışdığınız zaman iş qovluğunda qeyd olunmamış dəyişikliklər varsa, bu məsləhətlərdən bəziləri bu işi qorumağa kömək edə bilər.
Çox sadə bir misal verək. Üzərində Hello world yazdıran super sadə bir Ruby faylımız var.
#! /usr/bin/env ruby
def hello
puts 'hello world'
end
hello()
Qovluğumuzda whitespace
adlı yeni bir branch yaradırıq və bütün Unix sətir sonlarını DOS xətt sonlarına dəyişdirərək sənədin hər sətirini ancaq whitespace ilə dəyişdiririk.
Sonra “hello world” yazısını “hello mundo” olaraq dəyişdiririk.
$ git checkout -b whitespace
Switched to a new branch 'whitespace'
$ unix2dos hello.rb
unix2dos: converting file hello.rb to DOS format ...
$ git commit -am 'Convert hello.rb to DOS'
[whitespace 3270f76] Convert hello.rb to DOS
1 file changed, 7 insertions(+), 7 deletions(-)
$ vim hello.rb
$ git diff -b
diff --git a/hello.rb b/hello.rb
index ac51efd..e85207e 100755
--- a/hello.rb
+++ b/hello.rb
@@ -1,7 +1,7 @@
#! /usr/bin/env ruby
def hello
- puts 'hello world'
+ puts 'hello mundo'^M
end
hello()
$ git commit -am 'Use Spanish instead of English'
[whitespace 6d338d2] Use Spanish instead of English
1 file changed, 1 insertion(+), 1 deletion(-)
İndi yenidən master
branch-a qayıdırıq və funksiya üçün bəzi sənədlər əlavə edirik.
$ git checkout master
Switched to branch 'master'
$ vim hello.rb
$ git diff
diff --git a/hello.rb b/hello.rb
index ac51efd..36c06c8 100755
--- a/hello.rb
+++ b/hello.rb
@@ -1,5 +1,6 @@
#! /usr/bin/env ruby
+# prints out a greeting
def hello
puts 'hello world'
end
$ git commit -am 'Add comment documenting the function'
[master bec6336] Add comment documenting the function
1 file changed, 1 insertion(+)
İndi isə whitespace
branch-da birləşdirmə etməyə çalışırıq və whitespace dəyişikliklərinə görə konfliktlər görəcəyik.
$ git merge whitespace
Auto-merging hello.rb
CONFLICT (content): Merge conflict in hello.rb
Automatic merge failed; fix conflicts and then commit the result.
Birləşməni Ləğv etmək
İndi bizim bir neçə seçimimiz var.
Əvvəlcə bu vəziyyətdən necə çıxacağımızı izah edək.
Əgər siz konfliktlərin olacağını gözləmirdinizsə və vəziyyətlə hələ çox işləmək istəmirsinizsə, sadəcə git merge --abort
ilə birləşməni ləğv edə bilərsiniz.
$ git status -sb
## master
UU hello.rb
$ git merge --abort
$ git status -sb
## master
git merge --abort
seçimi birləşmədən əvvəlki vəziyyətə qayıtmağa çalışır.
Onun mükəmməl bir şəkildə işləyə bilməyəcəyi yeganə hallar, işlədiyiniz qovluqda açılmamış, buraxılmamış dəyişikliklərin olması ola bilər, əks halda yaxşı işləməlidir.
Hər hansı bir səbəbdən yenidən başlamaq istəsəniz, təkrar git reset --hard HEAD
işlədə bilərsiniz və bu zaman depolarınız son vəziyyətinə qaytarılacaq.
Yadda saxlayın ki, hər hansı bir iş itirilə bilər, ona görə də dəyişikliklərinizdən heç birini istəmədiyinizdən əmin olun.
Whitespace-ə Məhəl Qoymamaq
Bu konkret vəziyyətdə, konfliktlər whitespace ilə əlaqədardır. Bunu bilirik, çünki məsələ sadədir, ancaq real vəziyyətlərdə konfliktə baxanda izah etmək çox asandır ki, hər xətt bir tərəfdən çıxarılır və digər tərəfdən yenidən əlavə olunur. Default olaraq, Git bu sətirlərin hamısının dəyişdirildiyini görür, buna görə də faylları birləşdirə bilmir.
Default birləşdirmə strategiyası arqumentlər götürə bilər və onlardan bir neçəsi whitespace dəyişikliklərinə məhəl qoymur.
Birləşmədə çox sayda whitespace probleminizin olduğunu görsəniz, bu dəfə -Xignore-all-space
və ya -Xignore-space-change
ilə yenidən ləğv edib təkrar edə bilərsiniz.
Birinci seçim xətləri müqayisə edərkən whitespace-i tamamilə gözdən keçirir, ikincisi bir və ya daha çox whitespace simvollarının ardıcıllığını ekvivalent olaraq qəbul edir.
$ git merge -Xignore-space-change whitespace
Auto-merging hello.rb
Merge made by the 'recursive' strategy.
hello.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Bu vəziyyətdə, faktiki fayl dəyişiklikləri bir-birinə zidd olmadığına görə, whitespace dəyişikliklərini görməməzlikdən gəldikdə, hər şey yaxşı birləşir. Komandanızda bəzən boşluqlardan nişanlara reformat etməyi sevən və ya əksinə edən biri varsa, bu sizin üçün bir xilaskardır.
Manual Faylı Yenidən Birləşdirmə
Git whitespace-i əvvəlcədən emal etməyi bacarsa da, dəyişikliklərin digər növləri vardır ki, onlarda Git avtomatik idarə edə bilmir, lakin dəyişdirilə bilən düzəlişlərdir. Misal olaraq, Git’in whitespace dəyişikliyini həll edə bilmədiyini iddia edək və bunu manual şəkildə edək.
Həqiqətən etməli olduğumuz şey, faktiki faylı birləşdirməyə cəhd etmədən əvvəl dos2unix
proqramı ilə birləşdirməyə çalışdığımız faylı işə salmaqdır.
Bəs bunu necə edə bilərik?
Əvvəlcə birləşmə konflikti vəziyyətinə giririk. Sonra, mənim versiyamın nüsxələrini, onların versiyasını (birləşdirdiyimiz branch-dan) və ümumi versiyadan (hər iki tərəfin branch-dan çıxdığı yerdən) surətlərini almaq istəyirik. Sonra onların tərəfini və ya öz tərəfimizi düzəltmək istəyirik və yenidən bu tək fayl üçün yenidən birləşdirməyə çalışırıq.
Üç fayl versiyasını əldə etmək əslində olduqca asandır.
Git, bu versiyaların hamısını əlaqəli nömrələri olan “stages” indeksində saxlayır.
Stage 1 ortaq kökdür, stage 2 sizin versiyanızdır və stage 3 MERGE_HEAD
-dan, birləşdiyiniz versiyadır (“theirs”).
Konfliktli faylın bu versiyalarının hər birinin bir nüsxəsini git show əmri və xüsusi bir sintaksis ilə çıxara bilərsiniz.
$ git show :1:hello.rb > hello.common.rb
$ git show :2:hello.rb > hello.ours.rb
$ git show :3:hello.rb > hello.theirs.rb
Bir az daha sərt keçid əldə etmək istəyirsinizsə, bu faylların hər biri üçün Git bloklarının əsl SHA-1-lərini əldə etmək üçün ls-files -u
Plumbing əmrindən də istifadə edə bilərsiniz.
$ git ls-files -u
100755 ac51efdc3df4f4fd328d1a02ad05331d8e2c9111 1 hello.rb
100755 36c06c8752c78d2aff89571132f3bf7841a7b5c3 2 hello.rb
100755 e85207e04dfdd5eb0a1e9febbc67fd837c44a1cd 3 hello.rb
:1:hello.rb
SHA-1 çubuğunu axtarmaq üçün sadəcə bir stenddir.
İndi işlədiyimiz qovluqda hər üç mərhələnin məzmunu olduğundan, whitespace məsələsini həll etmək üçün onları manual şəkildə düzəldə bilərik və yalnız bunu az tanınan git merge-file
əmri ilə faylı yenidən birləşdirə bilərik.
$ dos2unix hello.theirs.rb
dos2unix: converting file hello.theirs.rb to Unix format ...
$ git merge-file -p \
hello.ours.rb hello.common.rb hello.theirs.rb > hello.rb
$ git diff -b
diff --cc hello.rb
index 36c06c8,e85207e..0000000
--- a/hello.rb
+++ b/hello.rb
@@@ -1,8 -1,7 +1,8 @@@
#! /usr/bin/env ruby
+# prints out a greeting
def hello
- puts 'hello world'
+ puts 'hello mundo'
end
hello()
Bu anda faylı qəşəng bir şəkildə birləşdirdik.
Əslində, bu, ignore-space-change
seçimindən daha yaxşı işləyir, çünki bu, sadəcə boş yerə dəyişiklik etmədən yerinə boşluq dəyişikliklərini düzəldir.
ignore-space-change
birləşməsində, işləri həqiqətən qarışıq hala gətirərək DOS xətti ucları ilə bir neçə xətt əldə edirik.
Əslində bir tərəf və ya digəri arasında dəyişdirilənin nə olduğu ilə əlaqədar bu tapşırığı bitirmədən əvvəl bir fikir əldə etmək istəyirsinizsə, git diff
-dan bu mərhələlərdən hər hansı birində birləşdirmə nəticəsində iş qovluğunuzda nə əmri verdiyinizi müqayisə etməsini istəyə bilərsiniz.
Hamısını izah edək.
Nəticəni birləşdirmədən əvvəl branch-nızda nə əldə etdiyinizi görmək, başqa sözlə birləşmənin nəyə tətbiq olunduğunu görmək üçün git diff --ours
proqramını işlədə bilərsiniz.
$ git diff --ours
* Unmerged path hello.rb
diff --git a/hello.rb b/hello.rb
index 36c06c8..44d0a25 100755
--- a/hello.rb
+++ b/hello.rb
@@ -2,7 +2,7 @@
# prints out a greeting
def hello
- puts 'hello world'
+ puts 'hello mundo'
end
hello()
Beləliklə, burada asanlıqla görə bilərik ki, branch-mızda baş verənlər, əslində bu birləşmə ilə bu faylı tanıdığımız vahid xətti dəyişdirir.
Birləşmənin nəticəsinin onların tərəfindəki vəziyyətdən necə fərqləndiyini görmək istəyiriksə, git diff --theirs
işlədə bilərik. Bu və aşağıdakı misalda biz təmizlənmiş hello.theirs.rb
faylı ilə deyil, Git-də olanlarla müqayisə etdiyimiz üçün whitespace-dən çıxarmaq üçün -b
istifadə etməliyik.
$ git diff --theirs -b
* Unmerged path hello.rb
diff --git a/hello.rb b/hello.rb
index e85207e..44d0a25 100755
--- a/hello.rb
+++ b/hello.rb
@@ -1,5 +1,6 @@
#! /usr/bin/env ruby
+# prints out a greeting
def hello
puts 'hello mundo'
end
Sonda siz faylın git diff --base
ilə hər iki tərəfdən necə dəyişdiyini görə bilərsiniz.
$ git diff --base -b
* Unmerged path hello.rb
diff --git a/hello.rb b/hello.rb
index ac51efd..44d0a25 100755
--- a/hello.rb
+++ b/hello.rb
@@ -1,7 +1,8 @@
#! /usr/bin/env ruby
+# prints out a greeting
def hello
- puts 'hello world'
+ puts 'hello mundo'
end
hello()
Bu zaman git clean
əmrini manual şəkildə birləşdirmək üçün yaratdığımız, lakin artıq lazım olmayan əlavə sənədləri silmək üçün istifadə edə bilərik.
$ git clean -f
Removing hello.common.rb
Removing hello.ours.rb
Removing hello.theirs.rb
Konfliktləri Yoxlamaq
Ola bilsin ki, indi hansısa səbəbdən həll ilə razı deyilik və ya bir və ya hər iki tərəfdən manual şəkildə düzəltmək yenə də yaxşı işləmədi və bizim daha çox kontekstə ehtiyacımız var.
Gəlin nümunəni bir az dəyişək. Bu nümunə üçün, hər ikisində bir neçə əmr yerinə yetirən, lakin birləşdikdə qanuni məzmun konflikti yaradan iki daha uzun branch var.
$ git log --graph --oneline --decorate --all
* f1270f7 (HEAD, master) Update README
* 9af9d3b Create README
* 694971d Update phrase to 'hola world'
| * e3eb223 (mundo) Add more tests
| * 7cff591 Create initial testing script
| * c3ffff1 Change text to 'hello mundo'
|/
* b7dcc89 Initial hello world code
İndi yalnız üç master
branch-da və üç mundo
branch-da yaşayan unikal əmrlər var.
mundo
branch-ı birləşdirməyə çalışarkən konflikt yaranır.
$ git merge mundo
Auto-merging hello.rb
CONFLICT (content): Merge conflict in hello.rb
Automatic merge failed; fix conflicts and then commit the result.
Biz birləşdirmə konfliktinin nə olduğunu görmək istəyirik. Bu zaman faylı açsaq, bu kimi bir şey görərik:
#! /usr/bin/env ruby
def hello
<<<<<<< HEAD
puts 'hola world'
=======
puts 'hello mundo'
>>>>>>> mundo
end
hello()
Birləşmənin hər iki tərəfi bu fayla məzmun əlavə etdi, lakin bəziləri bu konfliktə səbəb olan yeri dəyişdirdi.
Bu konfliktin necə yarandığını müəyyənləşdirmək üçün indi əlinizdə olan bir neçə vasitəni araşdıraq. Bəlkə də bu konflikti dəqiq necə həll edə biləcəyiniz tam bəlli deyil. Daha çox kontekstə ehtiyacınız var.
Digər bir faydalı vasitə --conflict
seçimi ilə git checkout
-dur. Bu, faylı yenidən yoxlayır və konflikt birləşmə işarələrini dəyişdirir.
O həm də, markerləri yenidən qurmaq və yenidən həll etmək istəsəniz də faydalı ola bilər.
Siz --conflict
ya diff3
ya da merge
(standart olandır) keçirə bilərsiniz.
Əgər siz onu diff3
-ə keçirsəniz, bu zaman Git konflikt markerlərinin bir az fərqli versiyasını istifadə edəcək, nəinki “ours” və “theirs” versiyalarını, həm də daha çox kontekst vermək üçün “base” versiyasını əlavə edəcək.
$ git checkout --conflict=diff3 hello.rb
Bunu işlədikdən sonra əvəzində fayl belə görünəcək:
#! /usr/bin/env ruby
def hello
<<<<<<< ours
puts 'hola world'
||||||| base
puts 'hello world'
=======
puts 'hello mundo'
>>>>>>> theirs
end
hello()
Bu formatı bəyənsəniz, merge.conflictstyle
parametrini diff3
-ə qoyaraq gələcək birləşdirmə konfliktləri üçün standart olaraq təyin edə bilərsiniz.
$ git config --global merge.conflictstyle diff3
git checkout
əmri variantları birləşdirmədən yalnız bir tərəfi və ya digərini seçmək üçün həqiqətən sürətli bir yol olan --ours
və --theirs
seçimlərini də istifadə edə bilərsiniz.
Bu, sadəcə bir tərəfi seçə biləcəyiniz və ya müəyyən bir faylları başqa bir branch-dan birləşdirmək istədiyiniz ikili sənədlərin ixtilafları üçün xüsusilə faydalı ola bilər. Yəni, birləşdirmədən və əmr vermədən əvvəl müəyyən faylları bir tərəfdən və ya digər tərəfdən yoxlamaq olar.
Birləşdirmə Log-u
Birləşmə konfliktlərink həll edərkən başqa bir faydalı vasitə isə git log
-dur.
Bu, konfliktlərə səbəb olan mövzularda kontekst əldə etməyə kömək edə bilər.
İki inkişaf xəttinin eyni kod sahəsinə toxunduğunu xatırlamaq üçün bir az tarixə nəzər salmaq bəzən faydalı ola bilir.
Bu birləşmədə iştirak edən hər iki branch-a daxil olan bütün unikal əmrlərin tam siyahısını əldə etmək üçün Üçqat Nöqtə-da öyrəndiyimiz “triple dot” sintaksisindən istifadə edə bilərik.
$ git log --oneline --left-right HEAD...MERGE_HEAD
< f1270f7 Update README
< 9af9d3b Create README
< 694971d Update phrase to 'hola world'
> e3eb223 Add more tests
> 7cff591 Create initial testing script
> c3ffff1 Change text to 'hello mundo'
Bu iştirak olunan altı ümumi tapşırığın, habelə hər bir inkişafın hansı xətt üzərində olmasının gözəl bir siyahısıdır.
Daha konkret kontekst vermək üçün bunu daha da asanlaşdıra bilərik. git log
-a --merge
seçimini əlavə etsək, yalnız konflikt yaradan bir fayla toxunan birləşmənin hər iki tərəfindəki əmrləri göstərəcəkdir.
$ git log --oneline --left-right --merge
< 694971d Update phrase to 'hola world'
> c3ffff1 Change text to 'hello mundo'
Bunun əvəzinə -p
seçimi ilə işləsəniz, konfliktlə nəticələnən fayldan yalnız fərqi əldə edirsiniz.
Bu, nəyə görə bir şeyin zidd olduğunu və onu daha ağıllı şəkildə həll etməyinizi başa düşməyinizə kömək etmək üçün lazım olan konteksti verməkdə həqiqətən faydalı ola bilər.
Kombinə olunmuş Diff Formatı
Git-in uğurlu olan birləşmə nəticələri mərhələli olduğundan, konflikt birləşdirmə vəziyyətində git diff
işlətsəniz hələ də konflikdə olanı əldə edəcəksiniz.
Bu hələ nəyi həll etməli olduğunuzu görmək üçün faydalı ola bilər.
Birləşdirmə konfliktindən sonra birbaşa git diff
işlətdiyiniz zaman sizə olduqca unikal fərqli fərqli bir çıxış formatında məlumat verəcəkdir.
$ git diff
diff --cc hello.rb
index 0399cd5,59727f0..0000000
--- a/hello.rb
+++ b/hello.rb
@@@ -1,7 -1,7 +1,11 @@@
#! /usr/bin/env ruby
def hello
++<<<<<<< HEAD
+ puts 'hola world'
++=======
+ puts 'hello mundo'
++>>>>>>> mundo
end
hello()
Format “Combined Diff” adlanır və hər bir sətrin yanında iki məlumat sütunu verir. Birinci sütun, bu sətir “ours” branch-mızla işləyən qovluğunuzdakı fayl arasında fərqli olduğunu (əlavə edilmiş və ya silinmiş) göstərir, ikinci sütun isə “theirs” branch ilə iş qovluğunun surətinin eyni olduğunu göstərir.
Beləliklə, bu misalda görə bilərsiniz ki, <<<<<<<
and >>>>>>>
xətləri işləmə nüsxəsindədir, lakin birləşmənin hər iki tərəfində deyil.
Bu o mənanı verir ki, birləşmə vasitəsi kontekstimiz üçün onları oraya yapışdırıb saxladı, lakin biz onları silməyi gözləyirdik.
Konflikti həll edib yenidən git diff
tətbiq etsək, eyni şeyi görəcəyik, amma bu bir az daha faydalıdır.
$ vim hello.rb
$ git diff
diff --cc hello.rb
index 0399cd5,59727f0..0000000
--- a/hello.rb
+++ b/hello.rb
@@@ -1,7 -1,7 +1,7 @@@
#! /usr/bin/env ruby
def hello
- puts 'hola world'
- puts 'hello mundo'
++ puts 'hola mundo'
end
hello()
Bu bizə göstərir ki, “hola world' işləmə nüsxəsində deyil, amma bizim tərəfimizdə idi, ``hello mundo” isə onların tərəfində idi, amma işləmə nüsxəsində deyildi və nəhayət “hello mundo” hər iki tərəfdə olmadığını halda işləyən nüsxədə idi. Bu qərar vermədən əvvəl nəzərdən keçirmək üçün faydalı ola bilər.
Siz bütün birləşdirmələrdə faktdan sonra məsələlərin necə həll olunduğunu görmək üçün git log
-dan istifadə edə bilərsiniz. Birləşdirmə git show
-u işlətdiyiniz təqdirdə və ya bir git log -p
-ə --cc
seçimi əlavə etsəniz, Git bu formatı çıxaracaqdır (bu standart olaraq yalnız birləşməmələr üçün patch-ları göstərir)
This shows us that “hola world” was in our side but not in the working copy, that “hello mundo” was in their side but not in the working copy and finally that “hola mundo” was not in either side but is now in the working copy. This can be useful to review before committing the resolution.
$ git log --cc -p -1
commit 14f41939956d80b9e17bb8721354c33f8d5b5a79
Merge: f1270f7 e3eb223
Author: Scott Chacon <schacon@gmail.com>
Date: Fri Sep 19 18:14:49 2014 +0200
Merge branch 'mundo'
Conflicts:
hello.rb
diff --cc hello.rb
index 0399cd5,59727f0..e1d0799
--- a/hello.rb
+++ b/hello.rb
@@@ -1,7 -1,7 +1,7 @@@
#! /usr/bin/env ruby
def hello
- puts 'hola world'
- puts 'hello mundo'
++ puts 'hola mundo'
end
hello()
Birləşdirməni Ləğv Etmək
Birləşdirmə əmrini necə yaratmağı bildiyiniz üçün səhv etmə ehtimalınız var. Git ilə işləməyin ən yaxşı tərəflərindən biri də odur ki, səhv etmək olar, çünki onları düzəltmək mümkündür (və bir çox hallarda asandır).
Birləşmə əmrləri heç fərqlənmir.
Deyək ki, bir mövzu branch-da işə başlamısınız, təsadüfən onu master
-ə birləşdirdiniz və indi əmr tarixçəniz belə görünür:
![Təsadüfi birləşdirmə commit-i](png/undomerge-start.png)
İstədiyiniz nəticənin nə olduğundan asılı olaraq bu problemə yaxınlaşmanın iki yolu var.
Referansları Düzəltmək
İstənilməyən birləşmə əməliyyatı yalnız yerli depolarınızda varsa, ən asan və ən yaxşı həll yolu istədiyiniz yeri göstərmələri üçün branch-ları köçürməkdir.
Əksər hallarda, git reset --hard HEAD~
ilə səhv edilmiş git merge
-i izləsəniz, bu branch göstəricilərini yenidən quracaq və buna görə də onlar belə görünəcəklər:
![`git reset --hard HEAD~`-dan sonra tarixçə](png/undomerge-reset.png)
git reset --hard HEAD~
-dan sonra tarixçəGeri qayıtmağı Reset Demystified-də izah etdik, buna görə burada nələrin baş verdiyini anlamaq çox çətin olmayacaq.
Sürətli bir xatırlatma: reset --hard
ümumiyyətlə üç addımdan keçir:
-
Branch-ın HEAD nöqtələrini bu yerə köçürün. Bu vəziyyətdə,
master
birləşmədən (C6
) əvvəl olduğu yerə köçürmək istəyirik. -
İndeksi HEAD kimi göstərin.
-
İşləmə qovluğunu indeks kimi göstərin.
Bu yanaşmanın mənfi tərəfi ortaq bir depo ilə problem yarada bilən tarixin yenidən yazılmasıdır.
Nə baş verə biləcəyi barədə daha çox məlumat almaq üçün Rebasing-in Təhlükələri-ə baxın; qısa versiyası odur ki, başqa insanların yazdığınız əmrləri varsa, yəqin ki, reset
etməkdən çəkinməlisiniz.
Birləşdirmədən bəri başqa əmrlər yaradılıbsa bu yanaşma da işləməyəcək; refs hərəkət bu dəyişiklikləri itirəcəkdir.
Commit-ləri Tərs Çevirmək
Əgər ətrafdakı branch işarətçisini sizin üçün işləməyəcəksə, Git, hazırda mövcud olandan bütün dəyişiklikləri ləğv edən yeni bir commit vermək seçimi verir. Git ssenaridə bu əməliyyatı “revert” adlandırır və siz onu bu şəkildə çağıracaqsınız:
$ git revert -m 1 HEAD
[master b1d8379] Revert "Merge branch 'topic'"
-m 1
flag-ı hansı valideynin “mainline” olduğunu göstərir və saxlanılmalıdır.
HEAD
-a (git merge topic
) birləşdirməyə çağırdığınız zaman, yeni əmrin iki valideyni olur: birincisi - HEAD
(C6
), ikincisi - (C4
) birləşən branch-ın ucu.
Bu vəziyyətdə, bütün məzmunu 1 saylı valideyndən (C6
) qorumaqla, 2 saylı valideynə (C4
) birləşdirməklə daxil edilmiş bütün dəyişiklikləri geri qaytarmaq istəyirik.
Commiti geri alma tarixi belə görünür:
![`git revert -m 1`-dən sonrakı tarixçə](png/undomerge-revert.png)
git revert -m 1
-dən sonrakı tarixçəYeni commit ^M
C6
ilə eyni məzmuna malikdir, buna görə də əgər buradan başlayaraq heç bir birləşmə baş verməyibsə, hal hazırda başlamamış əmrlər hələ də HEAD
-in tarixçəsində qalır.
Siz topic
-i yenidən master
-ə birləşdirməyə çalışsanız, Git çaşacaq:
$ git merge topic
Already up-to-date.
Artıq master
-də əlçatmaz bir topic
yoxdur.
Daha pisi isə, əgər topic
-ə iş əlavə etsəniz və yenidən birləşdirsəniz, Git yalnız geri qaytarıldıqdan sonrakı dəyişiklikləri göstərəcək:
![Yaxşı olmayan Birləşdirmə Tarixçəsi](png/undomerge-revert2.png)
Bunun ən yaxşı yolu orijinal birləşməni geri qaytarmaqdır, çünki indi geri qaytarılmış dəyişiklikləri gətirmək, daha sonra isə yeni birləşmə commit-i yaratmaq istəyirsiniz:
$ git revert ^M
[master 09f0126] Revert "Revert "Merge branch 'topic'""
$ git merge topic
![Geri çevrilmiş birləşməni yenidən birləşdirdikdən sonrakı tarixçə](png/undomerge-revert3.png)
Bu nümunədə,M
və ^M`ləğv olunur. `^^M
, C3
və C4
dəyişiklikləri təsirli bir şəkildə birləşdirir və C7
-nin dəyişikliklərindəki` C8 birləşir, buna görə də `topic
tamamilə birləşdirilmişdir.
Birləşdirmənin Digər Tipləri
Biz indiyə qədər birləşmənin “recursive” strategiyası adlandırılan iki branch-ın normal birləşməsini izah etdik. Bununla birlikdə branch-ları birləşdirməyin başqa yolları da var. Bir neçəsini sürətlə izah edək.
Our və ya Theirs Üstünlükləri
Əvvəla, normal “recursive” birləşmə rejimi ilə edə biləcəyimiz başqa bir faydalı şey də var.
ignore-all-space
və ignore-space-change
variantlarını -X
ilə keçdiyini gördük, ancaq Git’in bir tərəfə və ya digərinə konflikt görəndə üstünlük verəcəyini söyləyə bilərik.
Standart olaraq, Git iki branch arasında bir konflikt görəndə, konflikt markerlərini kodunuza əlavə edəcək və faylı konflikt olaraq qeyd edəcək və onu həll etməyə imkan verəcəkdir.
Git’in sadəcə konkret bir tərəf seçməsini və konflikti manual olaraq həll etməyinizin əvəzinə digər tərəfi görməməzliyə gəlməsini istəsəniz, birləşdirmə əmrini ya -Xours
ya da -Xtheirs
-ə verə bilərsiniz.
Git bunu görsə, konflikt markerlərini əlavə etməyəcəkdir. Birləşə bilən fərqlər birləşəcəkdir. Konfliktdə olan hər hansı bir fərq, sadəcə ikili sənədlər daxil olmaqla bütövlükdə göstərdiyiniz tərəfi seçəcəkdir.
Əvvəllər istifadə etdiyimiz “hello world” nümunəsinə qayıtsaq, branch-ımızda birləşməyin konfliktlərə səbəb olduğunu görə bilərik.
$ git merge mundo
Auto-merging hello.rb
CONFLICT (content): Merge conflict in hello.rb
Resolved 'hello.rb' using previous resolution.
Automatic merge failed; fix conflicts and then commit the result.
Hər şəkildə əgər -Xours
və ya `-Xtheirs`işlətsək bu alınmayacaq.
$ git merge -Xours mundo
Auto-merging hello.rb
Merge made by the 'recursive' strategy.
hello.rb | 2 +-
test.sh | 2 ++
2 files changed, 3 insertions(+), 1 deletion(-)
create mode 100644 test.sh
Bu vəziyyətdə, o, bir tərəfdən “hello mundo” və digər tərəfdən “hola world” olan sənəddə konflikt nişanları almaq əvəzinə, sadəcə “hola world” olanı seçəcəkdir. Bununla birlikdə, bu branch-dakı digər konfliktli dəyişikliklər uğurla birləşdirilir.
Bu seçim ayrıca fərdi fayl birləşməsi üçün git merge-file --ours
kimi bir şey işlədərək əvvəllər gördüyümüz git merge-file
əmrinə keçə bilər.
Buna bənzər bir iş görmək istəyirsinizsə, lakin Git-in digər tərəfdən dəyişiklikləri birləşdirməyə cəhd etməməsini istəyirsinizsə, “ours” birləşmə strategiyasından daha sərt bir seçim var. Bu, “ours” rekursiv birləşmə seçimindən fərqlidir.
Bu, əsasən saxta bir birləşmə edəcəkdir. Hər iki branch-la birlikdə valideynlər kimi yeni bir birləşmə qeyd edəcək, ancaq qoşulduğunuz branch-a belə baxmayacaq. Sadəcə cari branch-dakı dəqiq kodu birləşdirmə nəticəsilə qeyd edəcək.
$ git merge -s ours mundo
Merge made by the 'ours' strategy.
$ git diff HEAD HEAD~
$
Gördüyünüz kimi olduğumuz branch-la birləşmənin nəticəsi arasında heç bir fərq yoxdur.
Bu əsasən Git-ə branch-ı daha sonra birləşdirəcək ikən bir branch-ın artıq birləşdirildiyini düşündürmək üçün tez-tez faydalı ola bilər.
Məsələn, bir release
branch-ını dayandırdığınızı və bunun üçün bir anda yenidən master
branch-nıza birləşdirmək istədiyinizi deyək.
Bu vaxt master
bəzi səhvlər release
branch-na geri göndərilməlidir.
Siz bugfix branch-ını release
branch-na birləşdirə bilərsiniz və eyni zamanda merge -s ours
branch-nı master branch-a birləşdirə bilərsiniz (düzəliş artıq olsa da), belə ki, daha sonra yenidən branch-ı birləşdirdiyiniz zaman bugfix-də heç bir konflikt olmur.
Subtree Birləşdirməsi
Subtree birləşdirmə ideyası odur ki, iki layihəniz var və layihələrdən biri digərinin alt kateqoriyası ilə əlaqələndirildiyini əhatə edir. Bir subtree birləşməsi göstərdiyiniz zaman, Git həmin an birinin digərinin subtree-si olduğunu anlamaq və lazımi şəkildə birləşdirmək üçün kifayət qədər ağıllıdır.
Gəlin mövcud bir layihəyə ayrı bir layihə əlavə etmək və sonra ikincinin kodunu birincinin alt bölməsinə birləşdirmək nümunəsini göstərək.
Əvvəlcə Rack tətbiqini layihəmizə əlavə edəcəyik. Rack layihəsini öz layihəmizdə uzaq bir remote olaraq əlavə edəcəyik və sonra öz branch-ında yoxlayacağıq:
$ git remote add rack_remote https://github.com/rack/rack
$ git fetch rack_remote --no-tags
warning: no common commits
remote: Counting objects: 3184, done.
remote: Compressing objects: 100% (1465/1465), done.
remote: Total 3184 (delta 1952), reused 2770 (delta 1675)
Receiving objects: 100% (3184/3184), 677.42 KiB | 4 KiB/s, done.
Resolving deltas: 100% (1952/1952), done.
From https://github.com/rack/rack
* [new branch] build -> rack_remote/build
* [new branch] master -> rack_remote/master
* [new branch] rack-0.4 -> rack_remote/rack-0.4
* [new branch] rack-0.9 -> rack_remote/rack-0.9
$ git checkout -b rack_branch rack_remote/master
Branch rack_branch set up to track remote branch refs/remotes/rack_remote/master.
Switched to a new branch "rack_branch"
İndi rack_branch
branch-mızda Rack layihəsinin kökü və master
branch-mızda öz layihəmiz var.
Birini, daha sonra isə digərini yoxlasanız, fərqli layihə köklərinə sahib olduqlarını görə bilərsiniz:
$ ls
AUTHORS KNOWN-ISSUES Rakefile contrib lib
COPYING README bin example test
$ git checkout master
Switched to branch "master"
$ ls
README
Bu qəribə bir anlayışdır. Depodakı branch-ların hamısı eyni layihənin branch-ları olmamalıdır. Çox yaygın deyil, çünki nadir hallarda faydalıdır, lakin branch-ların tamamilə fərqli tarixə sahib olmasını əldə etmək olduqca asandır.
Bu vəziyyətdə, Rack layihəsini alt layihə olaraq master
proyektimizə çəkmək istəyirik.
Bunu git read-tree
ilə Git-də edə bilərik.
read-tree
və onun dostları haqqında Git’in Daxili İşləri-də daha çox məlumat əldə edəcəksiniz, ancaq indi onun bir branch-ın kök ağacını cari hazırlama sahənizdə və iş qovluğunda oxuduğunu bilin.
Yenidən master
branch-a qayıtdıq və rack_branch
branch-nı əsas layihəmizin master
branch-ın rack
alt bölməsinə pull edirik:
$ git read-tree --prefix=rack/ -u rack_branch
Commit zamanı, bütün alt Rack fayllarımız alt bölümdə olduğu kimi görünür - sanki biz onları tarball-dan köçürmüşük. Maraqlı olan budur ki, dəyişiklikləri branch-ların birindən digərinə qədər asanlıqla birləşdirə bilərik. Beləliklə, Rack layihəsi yenilənirsə, o branch-a keçərək üstdəki dəyişiklikləri pull edə bilərik:
$ git checkout rack_branch
$ git pull
Sonra biz bu dəyişiklikləri yenidən master
branch-mıza birləşdirə bilərik.
Dəyişiklikləri pull etmək və commit mesajını qabaqcadan hazırlamaq üçün --squash
seçimini, həmçinin recursive birləşmə strategiyasının -Xsubtree
seçimini istifadə edin.
Rekursiv strategiya burada standartdır, lakin aydınlıq üçün onu da daxil edirik.
$ git checkout master
$ git merge --squash -s recursive -Xsubtree=rack rack_branch
Squash commit -- not updating HEAD
Automatic merge went well; stopped before committing as requested
Rack layihəsindəki bütün dəyişikliklər birləşdirilmiş və yerli olaraq həyata keçirilməyə hazırdır.
Siz bunun əksini də edə bilərsiniz - master
branch-ınızın rack`subdirectory-sində dəyişikliklər aparın və sonra onları `rack_branch
branch-a birləşdirin və onları maintainers-ə təqdim edin və ya yuxarı tərəfə push edin.
Bu, submodule-lərdən istifadə etmədən (biz Alt Modullar-də əhatə edəcəyik) istifadə etmədən submodule-un iş axınına bir qədər bənzəyən bir iş axınına sahib olmaq üçün bir imkan verir. Digər branch layihələri ilə branch-larımızı depolarımızda saxlaya bilərik və onları bəzən layihəmizə birləşdirə bilərik. Bəzi yollarla yaxşıdır, məsələn, bütün kodlar bir yerə sadiqdir. Bununla birlikdə, digər çatışmazlıqları var ki, dəyişiklikləri yenidən birləşdirmək və ya təsadüfən bir-birinə bağlı olmayan bir depozitə basaraq səhv etmək daha az mürəkkəbdir və səhv etmək daha asandır.
Başqa bir qəribəlik də rack
alt qovluğunuzdakılar ilə rack_branch
branch-nızdakı kod arasındakı fərqi əldə etmək - onları birləşdirməyin lazım olub-olmadığını görməkdir - çünki, normal diff
əmrindən istifadə edə bilməyəcəksiniz.
Bunun əvəzinə müqayisə etmək istədiyiniz branch-la git diff-tree
işlətməlisiniz:
$ git diff-tree -p rack_branch
Və ya, rack
alt qovluğunuzda olanı, serverdəki master
branch-ı sonuncu dəfə gətirdiyinizlə müqayisə etmək üçün bunu işlədə bilərsiniz:
$ git diff-tree -p rack_remote/master