Учтите, что есть ветка A. Я создал 2 ветки A1, A2 из ветки A. Снова создал ветку A21 из ветки A2. Я изменил строку № 2 в X-файле и сделал фиксацию и отправку в A21. Теперь я объединил эти изменения в A2. Теперь я изменил кассу на A2. когда я объединяю источник/A, конфликта нет.. Как? Я узнал, что во время слияния, если есть разница в той же строке или удалении файла, возникает конфликт. Но в вышеупомянутом сценарии изменения, сделанные в A2, остаются прежними после слияния, и конфликт также не возникает ... кто-нибудь может объяснить, почему.
Когда я объединяю две ветки, в которых есть файл с разницей в одной строке, конфликт не возникает ... как?
Ответы (3)
Во-первых: не смотрите на имена веток. Посмотрите на коммиты и график коммитов. Вы будете использовать имена только для поиска самих коммитов, после этого вы используете граф. Воспользуйтесь просмотрщиком графиков или запустите git log --graph
(возможно, также и с --all --decorate --oneline
). Вы увидите изображения или текст со строкой, соединяющей коммиты с их родительскими коммитами, образующими древовидную или графическую структуру:
* a123456 last commit on A1
* a123457 another commit on A1
| * a2fedcb last commit on A2
|/
* a0dead0 latest shared commit reachable from both A1 and A2
.
.
.
например, или посмотрите изображение ниже от этот ответ до Просмотр полного дерева версий в git.
Когда у вас есть диаграмма, должно стать относительно ясно, что означает термин объединить базу. База слияния двух конкретных коммитов — это коммит, который разделяют две ветки. В приведенном выше выводе это будет коммит a0dead0
.
Если мы перерисуем график по горизонтали, может быть яснее, как расходятся две ветви:
o--...--X <-- you-are-on-this-branch (HEAD)
/
...--o--*
\
o--...--Y <-- you-ask-to-merge-this
Здесь коммит *
— это база для слияния, коммит X
— коммит, который вы проверили прямо сейчас, — это HEAD
, а коммит Y
— это другой коммит, который вы просите объединить.
Теперь принцип работы git merge
, по сути, заключается в том, чтобы начать с самой базы слияния. Git извлекает базовый коммит слияния и просматривает оба ваших коммита кончика ветки X
и Y
. Git сравнивает базу слияния с коммитом X
, чтобы увидеть, что вы сделали:
git diff --find-renames <hash-of-*> <hash-of-X>
Затем Git сравнивает базу слияния с коммитом Y
, чтобы увидеть, что они сделали:
git diff --find-renames <hash-of-*> <hash-of-Y>
Теперь Git просто объединяет два набора изменений, применяет их все ко всему, что находится в базе слияния, и, если все идет хорошо, создает новый коммит слияния, который также перемещает вашу текущую ветку:
o--...--X
/ \
...--o--* M <-- you-are-on-this-branch (HEAD)
\ /
o--...--Y <-- you-ask-to-merge-this
Два родителя слияния — это два коммита, которые были объединены, т. е. X
и Y
, в указанном порядке.
Слияние успешно, если Git может объединить изменения.
Слияние не удается, если Git не может объединить изменения.
Если вы и они внесли одно и то же изменение в одинаковую строку(и) одних и тех же файлов, Git может очень легко объединить эти два изменения, сделав одну копию изменения. Вот что делает Git.
Возникнет конфликт, если вы внесли различные изменения в одинаковые строки из базы слияния (коммит *
).
Git немного оптимизирует весь этот процесс, и зачастую ему вообще не нужно физически извлекать коммит *
, но в принципе именно так работает слияние.
(Пример изображения gitk
)
В дополнение к тому, что сказал @torek, git
будет иметь дело со слиянием без конфликтов, когда изменения идентичны, даже если изменения были внесены независимо.
Здесь я делаю идентичные изменения в том же файле в branch1
и branch2
независимо друг от друга, а затем объединяю branch2
в branch1
.
/mnt/c/git/ConsoleApp1 (branch1)>git commit -a -m "Adding Foo in branch1"
[branch1 c03dcc2] Adding Foo in branch1
1 file changed, 4 insertions(+)
/mnt/c/git/ConsoleApp1 (branch1)>git checkout develop
error: pathspec 'develop' did not match any file(s) known to git.
/mnt/c/git/ConsoleApp1 (branch1)>git checkout master
Switched to branch 'master'
/mnt/c/git/ConsoleApp1 (master)>git checkout -b branch2
Switched to a new branch 'branch2'
/mnt/c/git/ConsoleApp1 (branch2)>git commit -a -m "Adding Foo in branch2"
[branch2 d433128] Adding Foo in branch2
1 file changed, 4 insertions(+)
/mnt/c/git/ConsoleApp1 (branch2)>git merge branch1
Merge made by the 'recursive' strategy.
Результат: нет конфликта.
В вашем описании вы говорите только об одном изменении:
Я изменил строку № 2 в файле X и зафиксировал и отправил на A21.
Вы никогда не говорите что-то вроде «... и в ветке A я изменил строку № 2 в X-файле на что-то другое и зафиксировал это».
Если это истинная ситуация (т. е. в игре было только одно изменение), то конфликт невозможен.
git
, но не эксперт, да? :'-) Боже мой, если да, то кто я? Ой. - person RomainValeri   schedule 02.08.2018