Я пытаюсь понять, как GitLab выполняет коммит слияния. У чистого git другое поведение, и не совсем понятно, зачем в GitLab требуются коммиты слияния.
Допустим, у нас есть пустой репозиторий и мы выполняем первый коммит с именем direct commit to branch
. Затем мы создаем ветку b-4
с двумя коммитами. Давайте объединим ветку b-4
в main
.
Примечание: имейте в виду, что мы используем метод Merge commit
с опцией сквоша. Подробнее читайте в Методы слияния.
После завершения слияния мы видим следующую историю в веб-интерфейсе GitLab (извините, это не скриншот):
Merge branch 'b-4' into 'main' d08bf37f
Squashed commit ebc509c2
direct commit to branch 34b29e2b
Я ожидаю увидеть что-то подобное в дереве git, когда запускаю команду git log --graph --decorate
:
* commit d08bf37ff7157d48354c001ac066a6a44aece33e (HEAD -> main, origin/main)
| Author: author_name <[email protected]>
| Date: Fri Jun 14 16:30:27 2024 +0300
|
| Merge branch 'b-4' into 'main'
|
| Squashed commit
|
| See merge request author_name/repo_name!1
|
* commit ebc509c25c945b63fbc3f387bb308a54b1006e90
| Author: author_name <[email protected]>
| Date: Fri Jun 14 16:30:27 2024 +0300
|
| Squashed commit
|
* commit 34b29e2b89d38439299feef0ac64b926ba9d5d38
Author: author_name <[email protected]>
Date: Fri Jun 14 16:29:09 2024 +0300
direct commit to branch
Но на самом деле я наблюдаю следующее:
* commit d08bf37ff7157d48354c001ac066a6a44aece33e (HEAD -> main, origin/main)
|\ Merge: 34b29e2 ebc509c
| | Author: author_name <[email protected]>
| | Date: Fri Jun 14 16:30:27 2024 +0300
| |
| | Merge branch 'b-4' into 'main'
| |
| | Squashed commit
| |
| | See merge request author_name/repo_name!1
| |
| * commit ebc509c25c945b63fbc3f387bb308a54b1006e90
|/ Author: author_name <[email protected]>
| Date: Fri Jun 14 16:30:27 2024 +0300
|
| Squashed commit
|
* commit 34b29e2b89d38439299feef0ac64b926ba9d5d38
Author: author_name <[email protected]>
Date: Fri Jun 14 16:29:09 2024 +0300
direct commit to branch
Merge: 34b29e2 ebc509c
?Статья Как внутри GitLab работает мерж-реквест со сквошом? не отвечает на мой вопрос.
«сквош» И «фиксация слияния»?
Но судя по вашему графику истории, похоже, что сначала выполняется git reset --soft "$(git merge-base "$target" "$branch")"
, затем git commit -m "$message"
и, наконец, обычный git checkout "$target" && git merge --no-ff "$branch"
.
Чтобы воспроизвести поведение слияния локально с помощью Git, используйте параметр --no-ff, который означает отсутствие перемотки вперед.
# selecting the main branch
git checkout main
# merging b-4 into main and creating a merge commit
git merge --no-ff b-4
Таким образом, данные коммиты всегда объединяются вместе, создавая коммит слияния, даже в тех случаях, которые можно было бы разрешить с помощью перемотки вперед.
С помощью --no-ff создайте фиксацию слияния во всех случаях, даже если вместо этого слияние можно было бы разрешить как ускоренную перемотку вперед.
У GitHub другое поведение, гораздо проще
Создание коммита сквош, а затем еще одного коммита слиянием едва ли имеет смысл, поскольку коммит слияния не добавляет никакой информационной ценности к результирующему графу. Однако один из возможных способов это имеет смысл — обеспечить непрерывность, когда в коммите слияния содержится информация о номере MR и названиях ветвей, и, по-видимому, именно поэтому GitLab предлагает эту опцию.
Чтобы это работало, коммит слияния по определению должен иметь двух родителей. Таким образом, фактический график, который вы видите в своем репозитории, верен. Я подозреваю, что единственная причина, по которой вы ожидали увидеть линейный график, заключается в том, что документация GitLab в настоящее время неверна. На этом изображении самый правый коммит не может быть коммитом слияния:
Я предполагаю, что если кто-то уведомит GitLab об ошибке, он исправит ее, чтобы в результирующем изображении отображался коммит слияния с двумя родительскими объектами: E
и коммит сквош. Пока они это исправляют, они могли бы также исправить предложение, чтобы четко указать, что это опция фиксации слиянием в сочетании с фиксацией Squash.
Что касается того, как коммит сжатия и слияния работает за кулисами, это, вероятно, что-то вроде этого:
# create a temp branch called feature-squash starting from main:
git switch -c feature-squash main
# Begin squash merge of the feature branch:
git merge feature --squash
# Complete squash merge of the feature branch
git commit -m "Squash feature branch into a single commit"
# Checkout main:
git switch main
# Force a merge commit on main for the squashed commit:
git merge feature-squash --no-ff -m "Force merge commit for Squash Merge"
Боковое примечание: при сжатии вы можете выбрать альтернативный метод Squash Merge, и тогда вы просто получите один линейный сжатый коммит без дополнительной (ненужной, за исключением, возможно, метаданных сообщения фиксации) коммита слияния вместе с ним. Однако, если вы не сжимаете и у вас более одного коммита, я лично рекомендую всегда принудительно выполнять коммит слияния, даже если возможна быстрая перемотка вперед, чтобы всю историю этой функции можно было различить из истории коммитов.
Сдавливание пул-реквестов всегда неправильно и это нужно делать.
@hlovdal Я в целом согласен с этим и обычно не разрешаю это в репозиториях, находящихся под моим контролем. Я предпочитаю, чтобы разработчики сами уничтожали свои ветки, если захотят. Человек, который научится делать это самостоятельно, станет человеком, который сможет навести порядок в своей ветке и создать (потенциально несколько) полезных коммитов.
Наконец мне удалось воспроизвести поведение GitLab «Слияние фиксации + сжатие». Судя по комментарию @knittl git reset --soft
получилось.
export branch=b-3
# switch to branch and fill it with fake data
git checkout -b ${branch}
echo $(date) >> data.txt
git add data.txt
git commit -am "data commit number 1"
echo $(date) >> data.txt
git commit -am "data commit number 2"
# compact all commits in branch into single one
git reset --soft "$(git merge-base main ${branch})"
git commit -am "squashed commit"
# go to main branch and perform a merge with no fast-forward option
git checkout main
git merge --no-ff ${branch}
# optional: remove branch
git branch -d ${branch}
Затем вы увидите следующее дерево git git log --graph --decorate --all
:
* commit 4de3015a0cea2a95592c6e2e7dd8ba750cb88627 (HEAD -> main)
|\ Merge: 86e6ea0 360ca0b
| | Author: author_name <[email protected]>
| | Date: Mon Jun 17 22:31:03 2024 +0300
| |
| | Merge branch 'b-3'
| |
| * commit 360ca0b842d0148485f4589aa734e6b6fe145be7
|/ Author: author_name <[email protected]>
| Date: Mon Jun 17 22:30:52 2024 +0300
|
| squashed commits
|
* commit 86e6ea0f8cdd7788261d48c60a15dd87c0bb4806
Author: author_name <[email protected]>
Date: Mon Jun 17 22:29:54 2024 +0300
initial commit to main
Кстати, согласно ответу @TTT о смысле функции «Объединить фиксацию» - «всю историю этой функции можно узнать из истории фиксации». Частично согласен, но сейчас есть более удобные способы добавлять в коммиты дополнительные данные о PR. Я имею в виду автоссылки в GitHub или перекрестные ссылки в GitLab.
В любом случае, спасибо вам, ребята, за ваши ответы
Если вам нужна линейная история, вам следует выбрать перебазирование, а не фиксацию слияния.