Есть "их" версия "git merge -s ours"? - PullRequest
767 голосов
/ 06 октября 2008

При объединении ветки темы "B" в "A" с использованием git merge возникают конфликты. Я знаю, что все конфликты могут быть решены с помощью версии в "B".

Мне известно о git merge -s ours. Но я хочу что-то вроде git merge -s theirs.

Почему его не существует? Как я могу достичь того же результата после конфликтующего слияния с существующими командами git? (git checkout каждый необъединенный файл из B)

ОБНОВЛЕНИЕ: «Решение» простого отказа от чего-либо из ветви A (точка фиксации слияния до версии дерева B) не является тем, что я ищу.

Ответы [ 18 ]

904 голосов
/ 29 июля 2010

Добавьте параметр -X к theirs. Например:

git checkout branchA
git merge -X theirs branchB

Все слится желаемым образом.

Единственное, что я видел, вызывает проблемы, если файлы были удалены из BranchB. Они отображаются как конфликты, если удаление выполнено чем-то другим, кроме git.

Исправить несложно. Просто запустите git rm с именем всех удаленных файлов:

git rm {DELETED-FILE-NAME}

После этого -X theirs должен работать как положено.

Конечно, выполнение фактического удаления с помощью команды git rm предотвратит конфликт в первую очередь.


Примечание : также существует опция более длинной формы. Чтобы использовать его, замените:

-X theirs

с:

--strategy-option=theirs
195 голосов
/ 11 февраля 2011

Возможное и проверенное решение для объединения ветви B в нашу проверенную ветвь A:

# in case branchA is not our current branch
git checkout branchA

# make merge commit but without conflicts!!
# the contents of 'ours' will be discarded later
git merge -s ours branchB    

# make temporary branch to merged commit
git branch branchTEMP         

# get contents of working tree and index to the one of branchB
git reset --hard branchB

# reset to our merged commit but 
# keep contents of working tree and index
git reset --soft branchTEMP

# change the contents of the merged commit
# with the contents of branchB
git commit --amend

# get rid off our temporary branch
git branch -D branchTEMP

# verify that the merge commit contains only contents of branchB
git diff HEAD branchB

Чтобы автоматизировать это, вы можете заключить его в скрипт, используя в качестве аргументов branchA и branchB.

Это решение сохраняет первого и второго родителя коммита слияния, как и следовало ожидать от git merge -s theirs branchB.

83 голосов
/ 06 октября 2008

Старые версии git позволяли вам использовать стратегию слияния "их":

git pull --strategy=theirs remote_branch

Но с тех пор это было удалено, как объясняется в этом сообщении Джунио Хамано (сопровождающий Git) Как отмечено в ссылке, вместо этого вы должны сделать это:

git fetch origin
git reset --hard origin

Остерегайтесь, однако, что это отличается от фактического слияния. Ваше решение, вероятно, является вариантом, который вы действительно ищете.

60 голосов
/ 03 ноября 2012

С тех пор я использовал ответ от Поля Пладийса. Я обнаружил, что вы можете сделать "нормальное" слияние, возникают конфликты, поэтому вы делаете

git checkout --theirs <file>

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

git merge <branch> -s theirs

Во всяком случае, усилия больше, чем было бы со стратегией слияния! (Это было протестировано с git версии 1.8.0)

54 голосов
/ 07 декабря 2014

Не совсем ясно, каков ваш желаемый результат, поэтому существует некоторая путаница в отношении «правильного» способа сделать это в ответах и ​​их комментариях. Я пытаюсь дать обзор и увидеть следующие три варианта:

Попробуйте объединить и использовать B для конфликтов

Это не"их версия для git merge -s ours", а "их версия для git merge -X ours" (что сокращенно от git merge -s recursive -X ours):

git checkout branchA
# also uses -s recursive implicitly
git merge -X theirs branchB

Это то, что, например, Ответ Алана У. Смита Да.

Использовать содержимое только из B

Это создает коммит слияния для обеих ветвей, но отменяет все изменения с branchA и сохраняет только содержимое с branchB.

# Get the content you want to keep.
# If you want to keep branchB at the current commit, you can add --detached,
# else it will be advanced to the merge commit in the next step.
git checkout branchB

# Do the merge an keep current (our) content from branchB we just checked out.
git merge -s ours branchA

# Set branchA to current commit and check it out.
git checkout -B branchA

Обратите внимание, что слияние совершает первый родительский элемент теперь с branchB, и только второй с branchA. Это то, что, например, Gandalf458 ответ делает.

Используйте содержимое только из B и сохраняйте правильный родительский порядок

Это настоящая "их версия для git merge -s ours". Он имеет то же содержание, что и в предыдущем варианте (т. Е. Только с branchB), но порядок родителей правильный, то есть первый родитель с branchA, а второй с branchB.

git checkout branchA

# Do a merge commit. The content of this commit does not matter,
# so use a strategy that never fails.
# Note: This advances branchA.
git merge -s ours branchB

# Change working tree and index to desired content.
# --detach ensures branchB will not move when doing the reset in the next step.
git checkout --detach branchB

# Move HEAD to branchA without changing contents of working tree and index.
git reset --soft branchA

# 'attach' HEAD to branchA.
# This ensures branchA will move when doing 'commit --amend'.
git checkout branchA

# Change content of merge commit to current index (i.e. content of branchB).
git commit --amend -C HEAD

Это то, что ответ Пола Пладийса делает (не требуя временной ветки).

20 голосов
/ 06 октября 2008

Я решил свою проблему, используя

git checkout -m old
git checkout -b new B
git merge -s ours old
14 голосов
/ 12 апреля 2012

Если вы находитесь на ветке A, сделайте:

git merge -s recursive -X theirs B

Проверено на git версии 1.7.8

8 голосов
/ 08 сентября 2013

При слиянии ветки темы "B" в "A" с помощью git merge возникают конфликты. Я> знаю, что все конфликты могут быть решены с помощью версии в "B".

Я знаю, что Git Merge - наш. Но я хочу что-то вроде git merge> -s их.

Я предполагаю, что вы создали ветку от master и теперь хотите объединиться с master, переопределяя все старые вещи в master. Это именно то, что я хотел сделать, когда наткнулся на этот пост.

Делайте именно то, что вы хотите сделать, за исключением того, что сначала объедините одну ветвь с другой. Я только что сделал это, и это отлично сработало.

git checkout Branch
git merge master -s ours

Затем извлеките мастер и объедините в нем свою ветку (теперь все пройдет гладко):

git checkout master
git merge Branch
6 голосов
/ 30 октября 2013

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

git merge --strategy=ours ref-to-be-merged

git diff --binary ref-to-be-merged | git apply --reverse --index

git commit --amend

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

Однако это не очень хорошо работает с подмодулями.

5 голосов
/ 13 мая 2013

См. Широко цитируемый ответ Хунио Хамано : если вы собираетесь отказаться от зафиксированного контента, просто откажитесь от коммитов или, во всяком случае, держите его вне основной истории. Зачем беспокоить всех в будущем, читая сообщения коммитов от коммитов, которым нечего предложить?

Но иногда есть административные требования или, возможно, какая-то другая причина. Для тех ситуаций, когда вам действительно нужно записывать коммиты, которые ничего не вносят, вы хотите:

(правка: вау, я раньше ошибся. Это работает.)

git update-ref HEAD $(
        git commit-tree -m 'completely superseding with branchB content' \
                        -p HEAD -p branchB    branchB:
)
git reset --hard
...