-
1. Начало
- 1.1 За Version Control системите
- 1.2 Кратка история на Git
- 1.3 Какво е Git
- 1.4 Конзолата на Git
- 1.5 Инсталиране на Git
- 1.6 Първоначална настройка на Git
- 1.7 Помощна информация в Git
- 1.8 Обобщение
-
2. Основи на Git
-
3. Клонове в Git
-
4. GitHub
-
5. Git инструменти
- 5.1 Избор на къмити
- 5.2 Интерактивно индексиране
- 5.3 Stashing и Cleaning
- 5.4 Подписване на вашата работа
- 5.5 Търсене
- 5.6 Манипулация на историята
- 5.7 Мистерията на командата Reset
- 5.8 Сливане за напреднали
- 5.9 Rerere
- 5.10 Дебъгване с Git
- 5.11 Подмодули
- 5.12 Пакети в Git (Bundling)
- 5.13 Заместване
- 5.14 Credential Storage система
- 5.15 Обобщение
-
6. Настройване на Git
- 6.1 Git конфигурации
- 6.2 Git атрибути
- 6.3 Git Hooks
- 6.4 Примерна Git-Enforced политика
- 6.5 Обобщение
-
7. Git и други системи
- 7.1 Git като клиент
- 7.2 Миграция към Git
- 7.3 Обобщение
-
8. Git на ниско ниво
- 8.1 Plumbing и Porcelain команди
- 8.2 Git обекти
- 8.3 Git референции
- 8.4 Packfiles
- 8.5 Refspec спецификации
- 8.6 Транспортни протоколи
- 8.7 Поддръжка и възстановяване на данни
- 8.8 Environment променливи
- 8.9 Обобщение
-
9. Приложение A: Git в други среди
-
10. Приложение B: Вграждане на Git в приложения
- 10.1 Git от команден ред
- 10.2 Libgit2
- 10.3 JGit
- 10.4 go-git
- 10.5 Dulwich
-
A1. Приложение C: Git команди
- A1.1 Настройки и конфигурация
- A1.2 Издърпване и създаване на проекти
- A1.3 Snapshotting
- A1.4 Клонове и сливане
- A1.5 Споделяне и обновяване на проекти
- A1.6 Инспекция и сравнение
- A1.7 Дебъгване
- A1.8 Patching
- A1.9 Email команди
- A1.10 Външни системи
- A1.11 Административни команди
- A1.12 Plumbing команди
3.2 Клонове в Git - Основи на клоновете код и сливането
Основи на клоновете код и сливането
Нека илюстрираме разклоняването и сливането с малък пример, какъвто може да срещнете в реалния живот. Ще следваме следните стъпки:
-
Работите по уеб сайт.
-
Създавате нов клон за нова статия, по която работите.
-
Извършвате някакви дейности по този клон.
В този момент, получавате обаждане за внезапно възникнал критичен проблем в друга част от сайта, който трябва да решите бързо. Ще направите следното:
-
Превключвате към работния (production) клон.
-
Създавате нов клон и решавате проблема в него.
-
След тест, че всичко в поправката е наред, сливате hotfix клона обратно в работния клон.
-
Превключвате отново към клона с новата статия и продължавате работа.
Основи на разклоняването
Първо, нека приемем, че работите по проекта си и вече имате няколко къмита в клона master
.
![Проста история на къмитите](png/basic-branching-1.png)
Решили сте, че трябва да работите по проблем #53 в issue-tracking системата, която ползва вашата компания.
За да създадете клон и превключите към него в същия момент, изпълнете командата git checkout
с параметър -b
:
$ git checkout -b iss53
Switched to a new branch "iss53"
Това е съкратена версия на командите:
$ git branch iss53
$ git checkout iss53
![Създаване на нов указател към branch](png/basic-branching-2.png)
Вие си работите по сайта и правите няколко къмита.
По време на този процес, клонът iss53
се премества напред, защото е текущ (това означава, че HEAD
указателят сочи към него):
$ vim index.html
$ git commit -a -m 'Create new footer [issue 53]'
![Клонът `iss53` се е преместил напред в процеса на работа](png/basic-branching-3.png)
iss53
се е преместил напред в процеса на работаСега получавате обаждане, че нещо не е наред с уебсайта и трябва да го оправите незабавно.
С Git, не е нужно да прилагате поправката заедно с промените, които се съдържат в iss53
клона и не е нужно да влагате усилия по отмяната на тези промени преди да можете да приложите спешната поправка в production версията на сайта.
Всичко, което трябва да направите е да превключите обратно към master
клона.
Обаче преди да направите това, отбележете, че ако работната ви директория или индексната област съдържат некъмитнати промени, които влизат в конфликт с клона, към който превключвате, Git няма да позволи превключването на клоновете.
Най-добре е да имате чист работен статус преди превключването.
Съществуват начини да заобиколите това (известно като stashing и commit amending), които ще разгледаме по-късно в Stashing и Cleaning.
Засега, нека приемем, че сте къмитнали промените си, така че може да се върнете в master
клона:
$ git checkout master
Switched to branch 'master'
В този момент, работната ви директория ще се превърти обратно до съдържанието, което е имала преди да започнете работа по проблем 53 и можете да се концентрирате в спешната поправка, която е необходимо да въведете. Това е важен момент за запомняне: когато превключвате между клоновете, Git връща работната директория до статуса, в който е била последния път, когато сте къмитнали в този клон. Системата добавя, изтрива и променя файловете автоматично, за да ви предостави работното копие на обектите в момента на последния ви къмит.
След това, имате да правите спешната поправка.
Нека създадем един hotfix
клон, по който да работим докато тя стане готова:
$ git checkout -b hotfix
Switched to a new branch 'hotfix'
$ vim index.html
$ git commit -a -m 'Fix broken email address'
[hotfix 1fb7853] Fix broken email address
1 file changed, 2 insertions(+)
![Hotfix клон произлизащ от `master` клона](png/basic-branching-4.png)
master
клонаМожете да пускате тестовете си, да се уверите, че поправката работи както се очаква и да слеете обратно вашия hotfix
клон в master
клона за да го пуснете в работния вариант.
Това се прави с командата git merge
:
$ git checkout master
$ git merge hotfix
Updating f42c576..3a0874c
Fast-forward
index.html | 2 ++
1 file changed, 2 insertions(+)
В съобщението от сливането ще забележите фразата “fast-forward”.
Понеже къмитът C4
, към който сочи клона hotfix
, който сляхте, беше директно след къмита C2
, Git просто премества указателя напред.
Казано по друг начин, когато се опитвате да слеете един къмит с друг такъв, който може да бъде достигнат следвайки историята на първия, Git опростява нещата премествайки указателя напред, защото не се налага да се върши работа по сливане на разклонен код. Това се нарича “fast-forward.”
Сега промяната ви е в snapshot-а на къмита сочен от master
клона и можете да пуснете промяната в реалния сайт.
![`master` е превъртян (fast-forwarded) към `hotfix`](png/basic-branching-5.png)
master
е превъртян (fast-forwarded) към hotfix
След като суперважната промяна е въведена, можете да се върнете обратно към работата, която вършехте преди обаждането.
Обаче, първо ще изтриете клона hotfix
, понеже вече не ви е нужен — master
клонът сочи към същото място.
Изтриването се прави с параметъра -d
на командата git branch
:
$ git branch -d hotfix
Deleted branch hotfix (3a0874c).
Сега можете да се прехвърлите към клона, в който си вършите обичайната работа по проблем 53 и да си я продължите.
$ git checkout iss53
Switched to branch "iss53"
$ vim index.html
$ git commit -a -m 'Finish the new footer [issue 53]'
[iss53 ad82d7a] Finish the new footer [issue 53]
1 file changed, 1 insertion(+)
![Работата продължава в клона `iss53`](png/basic-branching-6.png)
iss53
Тук си струва да отбележим, че промените, които направихте в клона hotfix
не се съдържат във файловете на клона iss53
.
Ако искате да ги имате, можете да слеете master
клона в iss53
изпълнявайки git merge master
, или пък можете да изчакате с интегрирането на тези промени докато дойде момента, в който решите че е време да слеете iss53
клона обратно в master
.
Сливане
Да кажем, че сте решили, че работата по проблем 53 е свършена и сте готови да я слеете в master
клона.
За да направите това, ще действате по същия начин, по който го направихте с клона hotfix
по-рано.
Всичко, което трябва да направите е да превключите към клона, в който искате да сливате и да изпълните git merge
:
$ git checkout master
Switched to branch 'master'
$ git merge iss53
Merge made by the 'recursive' strategy.
index.html | 1 +
1 file changed, 1 insertion(+)
Това обаче изглежда по-различно от hotfix
сливането.
В този случай, историята на разработката се е отклонила от по-ранна точка.
Понеже къмитът на клона, в който сте (С4), не е директен предшественик на клона, който сливате, Git ще има малко работа за вършене.
В този случай, Git прави просто трипосочно сливане използвайки двата snapshot-а на клоновете и общия им предшественик (С2).
![Три snapshot-а използвани в типично сливане](png/basic-merging-1.png)
Това се нарича сливащ къмит (merge commit) и е специален заради това, че има повече от един родител. Вместо просто да премести указателя на клона напред, Git създава нов snapshot, който е резултат от това трипосочно сливане и автоматично създава нов къмит, който да сочи към него.
![Сливащ commit](png/basic-merging-2.png)
Сега, когато работата ви е слята, вече не се нуждаете от клона iss53
.
Можете да затворите проблема в issue-tracking системата и да изтриете клона:
$ git branch -d iss53
Конфликти при сливане
Понякога обаче, сливането не минава гладко.
Ако сте променили една и съща част от един и същи файл в различни клонове, които искате да слеете, Git няма да може да направи това чисто.
Ако промените ви по проблем #53 са модифицирали една и съща част от файл с тези от клона hotfix
, ще се получи конфликт при сливането, съобщението за който може да изглежда по подобен начин:
$ git merge iss53
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.
Git не е извършил merge къмита.
Процесът е прекъснат докато не разрешите конфликта
Ако искате да видите кои файлове не са слети вследствие на конфликта, можете да изпълните git status
:
$ git status
On branch master
You have unmerged paths.
(fix conflicts and run "git commit")
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: index.html
no changes added to commit (use "git add" and/or "git commit -a")
Всичко, по което има конфликти при сливането се показва като unmerged. Git добавя стандартни маркери за разрешаване на конфликта към файловете, в които има такъв, така че можете да ги отворите ръчно и да ги коригирате. Файлът ви ще съдържа секция подобна на тази:
<<<<<<< HEAD:index.html
<div id="footer">contact : email.support@github.com</div>
=======
<div id="footer">
please contact us at support@github.com
</div>
>>>>>>> iss53:index.html
Това означава, че версията в HEAD
(вашият master
клон, понеже той е текущия, в който сте изпълнили командата по сливането) е горната част на този блок (всичко преди =======
), докато версията в клона iss53
е в долната част.
За да решите конфликта, трябва да изберете една от двете или да слеете съдържанието сами.
Например, можете да замените целия блок с това:
<div id="footer">
please contact us at email.support@github.com
</div>
Това решение съдържа по малко от всяка секция и редовете <<<<<<<
, =======
, >>>>>>>
се изтриват напълно.
След като направите това за всяка секция и всеки файл в който има конфликти, изпълнете git add
за всеки файл, за да го маркирате като коригиран.
Индексирането на файл в Git го маркира като коректен, без конфликти.
Ако желаете да използвате графичен инструмент за решаването на конфликти, можете да изпълните git mergetool
, което ще стартира подходящия визуален инструмент и ще ви води през конфликтите подред:
$ git mergetool
This message is displayed because 'merge.tool' is not configured.
See 'git mergetool --tool-help' or 'git help config' for more details.
'git mergetool' will now attempt to use one of the following tools:
opendiff kdiff3 tkdiff xxdiff meld tortoisemerge gvimdiff diffuse diffmerge ecmerge p4merge araxis bc3 codecompare vimdiff emerge
Merging:
index.html
Normal merge conflict for 'index.html':
{local}: modified file
{remote}: modified file
Hit return to start merge resolution tool (opendiff):
Ако желаете да използвате инструмент различен от подразбиращия се (в случая Git е избрал opendiff
, защото командата е пусната на Mac), можете да видите всички поддържани такива в горната част на изхода от командата след надписа “one of the following tools.”
Просто напишете името на инструмента, който предпочитате.
Забележка
|
Ако се нуждаете от по-модерни инструменти за разрешаване на заплетени конфликти, обръщаме повече внимание на това в Сливане за напреднали. |
След като затворите инструмента, Git ви пита дали сливането е успешно.
Ако кажете това на скрипта, системата ще индексира файла и ще го маркира като коректен.
Можете да пуснете git status
отново за да проверите дали всички конфликти са разрешени:
$ git status
On branch master
All conflicts fixed but you are still merging.
(use "git commit" to conclude merge)
Changes to be committed:
modified: index.html
Ако това ви устройва и сте проверили, че всичко по което е имало конфликти е в индекса, можете да изпълните git commit
за да завършите сливащия къмит.
Къмит съобщението по подразбиране изглежда подобно на това:
Merge branch 'iss53'
Conflicts:
index.html
#
# It looks like you may be committing a merge.
# If this is not correct, please remove the file
# .git/MERGE_HEAD
# and try again.
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# All conflicts fixed but you are still merging.
#
# Changes to be committed:
# modified: index.html
#
Ако мислите, че за другите ви колеги гледащи кода по-късно ще е полезно да разберат как сте разрешили конфликта, можете да промените къмит съобщението с обяснение за това.