Просто чтобы развить существующий ответ, вот сценарий, который вы можете разыграть, не выходя из собственного дома, чтобы продемонстрировать, насколько легко так называемое сквош-слияние может привести к конфликту.
Начнем с того, что создадим файл на master
и зафиксируем его:
$ git init
$ echo "a" >> a.txt
$ git add .
$ git commit -m'start'
Теперь мы создаем develop
и модифицируем этот файл:
$ git branch develop
$ git checkout develop
$ echo "b" > a.txt
$ git add .
$ git commit -m'changed a to b'
Мы возвращаемся к master
и делаем сквош-слияние, и, кажется, все работает нормально:
$ git checkout master
$ git merge --squash develop
$ git commit -m'a squash commit from develop'
Все идет нормально. Теперь мы совершаем ужасную ошибку: мы делаем это снова. Мы переключаемся на develop
и еще немного модифицируем этот файл:
$ git checkout develop
$ echo "c" > a.txt
$ git add .
$ git commit -m'changed b to c'
Возвращаемся к master
и снова делаем сквош-слияние:
$ git checkout master
$ git merge --squash develop
Аааааааааааааааааааааааа у нас конфликт. Игра закончена.
Что случилось? Ну, проблема в том, что сквош-слияние не слияние. Это своего рода самодельный пластырь. Он создает конфигурацию индекса (промежуточной области), и вы фиксируете ее. В моем постановлении выше мы совершили это как отдельный шаг; с GitHub это сделано для вас. Но дело в том, что этот коммит, хотя и содержит изменения, которые произошли бы в результате реального слияния, не коммит слияния: это просто обычный коммит, как если бы вы сами внесли эти изменения, работая непосредственно над master
.
Итак, что значит внести изменения, которые произошли бы в результате реального слияния? Чтобы ответить на этот вопрос, вы должны знать, как работает слияние:
Слияние начинается с вычисления общей точки, из которой расходятся сливающиеся ветви: база слияния.
Затем он вычисляет две разницы: от базы слияния до конца первой ветви и от базы слияния до конца второй ветви.
Наконец, он вводит оба различия в базу слияния.
Хорошо, попробуйте сами, используя мысленный эксперимент.
Для первого слияния сквоша в моем вышеприведенном сценарии база слияния — start, где a.txt — это файл a. Так:
На master
это все еще a, поэтому нет необходимости вводить различия.
На develop
это b, поэтому разница будет change-a-to-b.
Итак, чтобы сформировать коммит слияния сквоша, мы просто меняем a на b.
Хорошо, давайте приступим ко второму слиянию сквоша в моем сценарии. Вот в чем дело: база слияния все еще запущена, где a.txt все еще a. Так:
master
разница будет change-a-to-b.
(Обратите внимание, что master
не знает, что это произошло из-за какого-либо слияния; он думает, что это изменение было выполнено независимо кем-то, работавшим непосредственно над master
.)
develop
разница будет change-a-to-c.
Но вы не можете делать и то, и другое; это конфликт!
Итак, вы видите, что проблема повторного использования ветки, которая ранее была слита, заключается в том, что база слияния не перемещается (и ничто в истории не связано с каким-либо слиянием); и поэтому каждое последующее слияние сквоша является потенциальным конфликтом с более ранним слиянием сквоша той же ветки.
person
matt
schedule
30.11.2020