Когда я объединяю две ветки, в которых есть файл с разницей в одной строке, конфликт не возникает ... как?

Учтите, что есть ветка A. Я создал 2 ветки A1, A2 из ветки A. Снова создал ветку A21 из ветки A2. Я изменил строку № 2 в X-файле и сделал фиксацию и отправку в A21. Теперь я объединил эти изменения в A2. Теперь я изменил кассу на A2. когда я объединяю источник/A, конфликта нет.. Как? Я узнал, что во время слияния, если есть разница в той же строке или удалении файла, возникает конфликт. Но в вышеупомянутом сценарии изменения, сделанные в A2, остаются прежними после слияния, и конфликт также не возникает ... кто-нибудь может объяснить, почему.


person Suba Shalini Subramaniam    schedule 02.08.2018    source источник
comment
Я здесь не эксперт, но у Git есть алгоритм слияния, который может решать проблемы автоматически, если он решит, что знает, что делать. Нет никакой гарантии, что каждое слияние будет приостанавливаться из-за конфликтов.   -  person Tim Biegeleisen    schedule 02.08.2018
comment
@TimBiegeleisen более 183 тыс. повторений и золотой тег git, но не эксперт, да? :'-) Боже мой, если да, то кто я? Ой.   -  person RomainValeri    schedule 02.08.2018
comment
@RomainVALERI Прочитайте ответ Торека ниже, и вы увидите, что я оцениваю себя как таковой :-)   -  person Tim Biegeleisen    schedule 02.08.2018
comment
@TimBiegeleisen Я неоднократно видел его сообщения, и это прекрасно :'-) Кроме того, мне жаль, что я начал этот чат не по теме здесь, хотя я знаю, что это не место. Я удалю свои комментарии позже сегодня ... боже, я люблю мерзавца.   -  person RomainValeri    schedule 02.08.2018


Ответы (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)

изображение из stackoverflow.com/a/18287861/1256452

person torek    schedule 02.08.2018

В дополнение к тому, что сказал @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.

Результат: нет конфликта.

person tymtam    schedule 02.08.2018

В вашем описании вы говорите только об одном изменении:

Я изменил строку № 2 в файле X и зафиксировал и отправил на A21.

Вы никогда не говорите что-то вроде «... и в ветке A я изменил строку № 2 в X-файле на что-то другое и зафиксировал это».

Если это истинная ситуация (т. е. в игре было только одно изменение), то конфликт невозможен.

person j6t    schedule 02.08.2018