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

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

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

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

UPDATE: "Решение" просто отбрасывания чего-либо из ветки A (точка фиксации слияния с B-версией дерева) не является тем, что я ищу.

Ответы

Ответ 1

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

git checkout branchA
git merge -X theirs branchB

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

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

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

git rm {DELETED-FILE-NAME}

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

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


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

-X theirs

с:

--strategy-option=theirs

Ответ 2

Возможное и проверенное решение для слияния branchB в нашем выписке branchA:

# 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

Чтобы автоматизировать его, вы можете связать его с script с помощью ветвей и ветвей в качестве аргументов.

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

Ответ 3

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


git pull --strategy=theirs remote_branch

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


git fetch origin
git reset --hard origin

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

Ответ 4

Я использовал ответ от Paul Pladijs с тех пор. Я узнал, вы можете сделать "нормальное" слияние, возникли конфликты, поэтому вы делаете

git checkout --theirs <file>

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

git merge <branch> -s theirs

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

Ответ 5

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

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

Это то, что отвечает Paul Pladijs (не требуя временной ветки).

Ответ 6

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

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

Ответ 7

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

git merge -s recursive -X theirs B

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

Ответ 8

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

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

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

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

git checkout Branch
git merge master -s ours

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

git checkout master
git merge Branch

Ответ 9

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

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

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

git commit --amend

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

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

Ответ 10

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

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

(edit: wow, мне удалось это сделать раньше. Это работает.)

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

Ответ 11

Этот использует дерево чтения команд wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww, но делает его более коротким в целом.

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>

Ответ 12

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

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

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

См. commit c25d98b (25 сентября 2017 г.) Junio ​​C Хамано (gitster).
(слияние Junio ​​C Hamano - gitster - в commit 4da3e23, 28 Sep 2017)

стратегии слияния: избегайте подразумевать, что существует < <22 >

Описание опции -Xours merge имеет скобку что говорит читателям, что он сильно отличается от -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' -

Ярослав Халченко пытается снова отстаивать эту стратегию, но Junio ​​C. Hamano добавляет:

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

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

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

Ответ 13

Это объединит ваш newBranch в существующем baseBranch

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

Ответ 14

git merge -Xtheirs <branch_name>

Ответ 15

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

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

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

Ответ 16

UPDATE

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


То, что вы ищете, не является противоположностью команды git merge -s ours, которую вы ищете против команды git merge -s recursive -X ours, которая git merge -s recursive -X theirs


Оригинальный ответ

с учетом исходных ветвей

*    0123456 (HEAD->A, origin/A)
| *  1234556 (origin/B, B)
|/
*    ??????? (common root)

чтобы объединить ветвь B в A, игнорируя состояние ветки A, сначала выполните регулярное слияние

git merge -s ours B    (this is the opposite of what we want)

это приводит к

*    2345678 (HEAD->A) Merge branch 'B' into A    (all wrong)
|\
* |  0123456 (origin/A)
| *  1234567 (origin/B, B)
|/
*    ??????? (common root)

не нажимайте это слияние, поскольку код фиксации изменится (и это неправильно в любом случае) теперь мы можем изменить, после того, что стратегия ours в стратегию theirs

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

git reset --hard B    (this is what we want the merge to look like (the merge can now only be referenced by the commit id `2345678`))
git reset --soft 2345678    (without changing any files go back to the merge)
git commit --amend    (branch B is now the final version of the merge)

теперь имеем

*    3456789 (HEAD->A) Merge branch 'B' into A    (correctly ignores changes from 0123456)
|\
* |  0123456 (origin/A)
| *  1234567 (origin/B, B)
|/
*    ??????? (common root)

$ diff HEAD B
[... no changes ...]
git push

сделать

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

Ответ 17

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

  • Org/repository1 master
  • Org/repository2 master

Я хотел, чтобы все изменения из repository2 master были применены к repository1 master, принимая все изменения, которые сделает репозиторий2. В терминах git это должна быть стратегия, называемая -s theirs, но она не существует. Будьте осторожны, потому что -X theirs назван так, как будто это будет то, что вы хотите, но это НЕ то же самое (он даже говорит об этом на странице руководства).

Как я решил, это перейти к repository2 и создать новую ветвь repo1-merge. В этой ветке я побежал git pull [email protected]:Org/repository1 -s ours, и он сливается отлично, без проблем. Затем я подталкиваю его к пульту дистанционного управления.

Затем я возвращаюсь к repository1 и создаю новую ветвь repo2-merge. В этой ветке я запускаю git pull [email protected]:Org/repository2 repo1-merge, который будет содержать проблемы.

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

Ответ 18

Эквивалент (который хранит родительский порядок), чтобы "объединить -s с их ветвью B"

Перед слиянием: 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}'