Github не может объединить ветку, не конфликты, вручную автоматически слияние

У меня есть запрос на pull, который Github говорит, что он не может автоматически сливаться. Это изменение за мастером несколько коммитов, но без конфликтов.

В ручном слиянии я не получаю никаких конфликтов, и я получаю этот вывод:

(on master)
$git merge otherbranch
[vim pops up for commit message, :wq]
Auto-merging <file>
Merge made by the 'recursive' strategy.
<file> | 1 +
1 file changed, 1 insertion(+)

Вот почему Github не может автоматически объединиться? В любом случае он автоматически объединяется из командной строки. Это недостаточно для Github?

Ответ 1

Причина в том, что git merge использует по умолчанию стратегию, называемую рекурсивной. Он способен выполнять трехстороннее слияние: с помощью патча с одной стороны и применения этого патча к другой стороне для создания нового файла. Он также делает это рекурсивно, в более сложных ситуациях, когда происходит много разветвлений и слияний, и существует несколько оснований слияния для объединения двух коммитов.

Недавно я столкнулся с такой же ситуацией:

$ git merge-base --all 90d64557 05b3dd8f
711d1ad9772e42d64e5ecd592bee95fd63590b86
f303c59666877696feef62844cfbb7960d464fc1
$

С двумя основаниями слияния невозможно трехстороннее слияние. Поэтому "рекурсивная" стратегия разрешила это, сначала перейдя в слияние этих двух коммитов:

$ git merge-base 711d1ad9 f303c596
3f5db59435ffa4a453e5e82348f478547440e7eb
$

ОК, только одна база слияния, поэтому может начаться трехстороннее слияние. какие изменения с обеих сторон?

$ git diff --stat 3f5db594 711d1ad9
 normalize/coll.py      | 116 ++++++++++++++++++++++++++++++++++++++-----------
 normalize/visitor.py   |  49 ++++++++++-----------
 tests/test_property.py |  10 +++--
 3 files changed, 120 insertions(+), 55 deletions(-)
$ git diff --stat 3f5db594 f303c596
 normalize/identity.py  | 38 +++++++++++++++++++++++++++++++-------
 tests/test_property.py |  2 ++
 2 files changed, 33 insertions(+), 7 deletions(-)
$ 

Эти два различия также вносили изменения в один и тот же файл, поэтому их нельзя разрешить с помощью простой стратегии просто взять новую версию каждого файла с каждой стороны (слияние индексов). Вместо этого git берет новый файл с одной стороны и пытается применить патч с другой стороны к нему. Результатом является комбинированный коммит, который можно моделировать следующим образом:

$ git checkout -b tmp
Switched to a new branch 'tmp'
$ git reset --hard f303c59666877696feef62844cfbb7960d464fc1
HEAD is now at f303c59 record_id: throw a more helpful error if record identity is not hashable
$ git merge 711d1ad9772e42d64e5ecd592bee95fd63590b86
Auto-merging tests/test_property.py
Merge made by the 'recursive' strategy.
 normalize/coll.py      | 116 ++++++++++++++++++++++++++++++++++++++-----------
 normalize/visitor.py   |  49 ++++++++++-----------
 tests/test_property.py |  10 +++--
 3 files changed, 120 insertions(+), 55 deletions(-)
$ git diff --stat 3f5db594 HEAD tests/test_property.py
 tests/test_property.py | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)
$

Затем он возвращается к исходному 3-стороннему слиянию, используя этот результат слияния как отправную точку; и это также включает изменения в один и тот же файл:

$ git diff --stat HEAD 90d64557| grep selector
 normalize/selector.py          |  17 +--
 tests/test_selector.py         |  19 ++--
$ git diff --stat HEAD 05b3dd8f| grep selector
 normalize/selector.py  | 29 +++++++++++++++++------------
 tests/test_selector.py |  9 +++++++++
$

Однако снова изменения относятся к разным разделам файла, и поэтому использование diff и применение его к другой стороне успешно.

Таким образом, C git смог разрешить это слияние, сначала выполнив трехстороннее слияние на двух основаниях слияния двух исходных точек, а затем выполнив другое трехстороннее слияние на двух исходных коммитах, объединенных и промежуточный результат первого слияния.

Автоматическое разрешение Github этого не делает. Это не обязательно неспособно, и я не уверен, какая часть рекурсивной стратегии она реализует, но это заблуждение на стороне осторожности, и это именно то, что вы ожидаете от этой большой зеленой кнопки: -).

Ответ 2

Нет, это не о слиянии . Речь идет о перезагрузке.

Вы должны попробовать и переустановить в своем локальном репо (клонированном свою вилку), otherbranch поверх master.

Во-первых, убедитесь, что мастер является последним из исходного репозитория upstream:

fork

cd /your/local/repo
git remote add upstream /url/original/repo
git fetch upstream

# Make sure you don't have any local commmit on your master
git branch -f master upstream/master # reset your master branch 
                                     # to the one from upstream repo
git checkout otherbranch
git rebase master

Эта rebase создаст конфликты, которые вы должны решить, git add, а затем git rebase --continue.

Наконец, просто push --force ваша ветка на свою вилку: , которая автоматически обновит ваш запрос на тягу (больше ничего не делать).

git push -u -f otherbranch origin

(если он уже был нажат один раз, один git push должен быть достаточно)

Подробнее см. дополнительные советы о том, как тянуть-запросы здесь.

Ответ 3

По умолчанию Git не знает, может ли он автоматически объединить вашу ветку или нет, прежде чем подтвердить сообщение фиксации для фиксации слияния.

Если вы знаете, что у вас не будет конфликтов, вы можете автоматизировать этот процесс рекурсивного автоматического слияния, изменив GIT_EDITOR на неинтерактивный инструмент, например, добавив cat или true:

GIT_EDITOR=true git merge otherbranch

То же самое для pull. Вы также можете указать стратегию слияния, например -X theirs или -X ours.

или другой метод - переустановка (добавление -r к вашей команде pull).