Что на самом деле делает GitLab «под капотом» при создании коммита слияния?

Я пытаюсь понять, как 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?
  • Что на самом деле происходит на низком уровне?
  • Как воспроизвести это поведение, используя чистый git?

Статья Как внутри GitLab работает мерж-реквест со сквошом? не отвечает на мой вопрос.

Если вам нужна линейная история, вам следует выбрать перебазирование, а не фиксацию слияния.

evolutionxbox 14.06.2024 16:57

«сквош» И «фиксация слияния»?

knittl 14.06.2024 18:06

Но судя по вашему графику истории, похоже, что сначала выполняется git reset --soft "$(git merge-base "$target" "$branch")", затем git commit -m "$message" и, наконец, обычный git checkout "$target" && git merge --no-ff "$branch".

knittl 14.06.2024 18:09
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
143
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Чтобы воспроизвести поведение слияния локально с помощью 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 другое поведение, гораздо проще

Egor Vasilyev 17.06.2024 21:33
Ответ принят как подходящий

Создание коммита сквош, а затем еще одного коммита слиянием едва ли имеет смысл, поскольку коммит слияния не добавляет никакой информационной ценности к результирующему графу. Однако один из возможных способов это имеет смысл — обеспечить непрерывность, когда в коммите слияния содержится информация о номере 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 17.06.2024 13:33

@hlovdal Я в целом согласен с этим и обычно не разрешаю это в репозиториях, находящихся под моим контролем. Я предпочитаю, чтобы разработчики сами уничтожали свои ветки, если захотят. Человек, который научится делать это самостоятельно, станет человеком, который сможет навести порядок в своей ветке и создать (потенциально несколько) полезных коммитов.

TTT 17.06.2024 16:48

Наконец мне удалось воспроизвести поведение 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.

В любом случае, спасибо вам, ребята, за ваши ответы

Другие вопросы по теме