it-swarm.com.ru

Есть "их" версия "git merge -s ours"?

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

Я знаю о git merge -s ours. Но я хочу что-то вроде git merge -s theirs.

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

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

770
elmarco

Добавьте параметр -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
911
Alan W. Smith

Возможное и проверенное решение для объединения ветки 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.

195
Paul Pladijs

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

git pull --strategy=theirs remote_branch

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

git fetch Origin
git reset --hard Origin

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

83
Pat Notz

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

git checkout --theirs <file>

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

git merge <branch> -s theirs

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

60
musicmatze

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

Попробуйте объединить и использовать 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

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

54
siegi

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

git checkout -m old
git checkout -b new B
git merge -s ours old
20
elmarco

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

git merge -s recursive -X theirs B

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

14
rafalmag

При слиянии ветки темы "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
8
Gandalf458

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

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

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

git commit --amend

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

Это не играет Ниццу с субмодулями как бы то ни было.

6
thoutbeckers

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

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

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

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

Почему его не существует?

Хотя в " команда git для создания одной ветви похожей на другую " я упоминаю, как имитировать git merge -s theirs, учтите, что Git 2.15 (4 квартал 2017 года) теперь более понятен:

Документация для -X<option> для слияний была введена в заблуждение, чтобы предположить, что существует -s theirs, а это не так.

См. commit c25d98b (25 сентября 2017 г.) по Junio ​​C Hamano (gitster) .
(Объединено Junio ​​C Hamano - gitster - в коммит 4da3e2 , 28 сентября 2017 г.)

стратегии слияния: избегайте намека на то, что "-s theirs" существует

Описание параметра слияния -Xours содержит заключенное в скобки примечание, которое сообщает читателям, что оно очень отличается от -s ours, что является правильным, но описание -Xtheirs, которое следует за ним небрежно, говорит "это противоположно ours", создавая ложное впечатление, что Читатели также должны быть предупреждены, что он сильно отличается от -s theirs, который на самом деле даже не существует.

-Xtheirs - это опция стратегии , применяемая к рекурсивной стратегии. Это означает, что рекурсивная стратегия будет по-прежнему объединять все, что только может, и в случае конфликтов будет прибегать к логике "theirs".

Эта дискуссия о целесообразности или нет стратегии слияния theirs была возобновлена ​​недавно в этой ветке за сентябрь 2017 года .
Это подтверждает старые (2008) темы

Короче говоря, предыдущее обсуждение можно резюмировать как "мы не хотим, чтобы -s theirs", поскольку это поощряет неправильный рабочий процесс ".

Упоминается псевдоним:

mtheirs = !sh -c 'git merge -s ours --no-commit $1 && git read-tree -m -u $1' -

Ярослав Хальченко пытается отстаивать эту стратегию еще раз но добавляет Хунио К. Хамано :

Причина, по которой наши и их не являются симметричными, заключается в том, что вы - это вы, а не они - контроль и владение нашей историей и их историей не симметричны.

Как только вы решите, что их история является основной, вы бы предпочли рассматривать вашу линию развития как побочную ветвь и выполнить слияние в этом направлении, то есть первый родительский результат получающегося слияния является коммитом в их истории, а второй Родитель последний плохой в вашей истории. Таким образом, вы бы в конечном итоге использовали "checkout their-history && merge -s ours your-history", чтобы сохранить разумность первого родителя.

И в этот момент использование "-s ours" больше не является обходным решением из-за отсутствия "-s theirs".
Это правильная часть желаемой семантики, т.е. с точки зрения сохранившейся канонической линии истории, вы хотите сохранить то, что она сделала, сводя на нет то, что другая строка истории сделал .

2
VonC

Этот использует дерево чтения команды git plumbing, но сокращает общий рабочий процесс.

git checkout <base-branch>

git merge --no-commit -s ours <their-branch>
git read-tree -u --reset <their-branch>
git commit

# Check your work!
git diff <their-branch>
2
Michael R

Этот ответ дал Пол Пладийс. Я просто взял его команды и сделал псевдоним для удобства.

Отредактируйте ваш .gitconfig и добавьте следующее:

[alias]
    mergetheirs = "!git merge -s ours \"$1\" && git branch temp_THEIRS && git reset --hard \"$1\" && git reset --soft temp_THEIRS && git commit --amend && git branch -D temp_THEIRS"

Затем вы можете "git merge -ssis A" запустив

git checkout B (optional, just making sure we're on branch B)
git mergetheirs A
0
Brain2000

Эквивалент (сохраняющий родительский порядок) "git merge -s itss branchB"

До слияния: enter image description here

!!! Убедитесь, что вы в чистоте!

Сделать слияние:

git commit-tree -m "take theirs" -p HEAD -p branchB 'branchB^{tree}'
git reset --hard 36daf519952 # is the output of the prev command

Что мы сделали ? Мы создали новый коммит, у которого два родителя - наш и их, а коннект коммита - BranchB - их

После слияния: enter image description here

Точнее:

git commit-tree -m "take theirs" -p HEAD -p 'SOURCE^{commit}' 'SOURCE^{tree}'
0
Boaz Nahum

Я думаю, что вы на самом деле хотите:

git checkout -B mergeBranch branchB
git merge -s ours branchA
git checkout branchA
git merge mergeBranch
git branch -D mergeBranch

Это кажется неуклюжим, но это должно работать. Единственное, что мне действительно не нравится в этом решении, это то, что история git будет сбивать с толку ... Но, по крайней мере, история будет полностью сохранена, и вам не нужно будет делать что-то особенное для удаленных файлов.

0
briemers

Это объединит ваш новый филиал с существующим базовым.

git checkout <baseBranch> // this will checkout baseBranch
git merge -s ours <newBranch> // this will simple merge newBranch in baseBranch
git rm -rf . // this will remove all non references files from baseBranch (deleted in newBranch)
git checkout newBranch -- . //this will replace all conflicted files in baseBranch
0
Pawan Maheshwari