Existe uma versão “deles” de “git merge -s ours”?

Ao mesclar o ramo de tópico “B” em “A” usando o git merge , eu recebo alguns conflitos. Eu sei que todos os conflitos podem ser resolvidos usando a versão em “B”.

Estou ciente do git merge -s ours . Mas o que eu quero é algo como git merge -s theirs .

Por que não existe? Como posso obter o mesmo resultado após a fusão conflitante com os comandos git existentes? ( git checkout todo arquivo não criado de B)

ATUALIZAÇÃO: A “solução” de apenas descartar qualquer coisa da ramificação A (o ponto de consolidação de mesclagem para a versão B da tree) não é o que estou procurando.

Adicione a opção -X à theirs . Por exemplo:

 git checkout branchA git merge -X theirs branchB 

Tudo vai se fundir da maneira desejada.

A única coisa que eu vi causar problemas é se os arquivos foram excluídos do branchB. Eles aparecem como conflitos se algo diferente de git fez a remoção.

A correção é fácil. Apenas execute git rm com o nome de todos os arquivos que foram excluídos:

 git rm {DELETED-FILE-NAME} 

Depois disso, o -X theirs deve funcionar como esperado.

Claro, fazer a remoção real com o comando git rm impedirá que o conflito aconteça em primeiro lugar.


Nota : Também existe uma opção de formulário mais longo. Para usá-lo, substitua:

 -X theirs 

com:

 --strategy-option=theirs 

Uma solução possível e testada para mesclar branchB em nosso branchA check-out:

 # 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 

Para automatizá-lo, você pode envolvê-lo em um script usando branchA e branchB como argumentos.

Essa solução preserva o primeiro e o segundo pai da consolidação de mesclagem, assim como você esperaria de git merge -s theirs branchB .

Versões mais antigas do git permitiram que você usasse a estratégia de mesclagem “theirs”:

 git pull --strategy=theirs remote_branch 

Mas isso já foi removido, conforme explicado nesta mensagem por Junio ​​Hamano (o mantenedor do Git). Conforme observado no link, você faria isso:

 git fetch origin git reset --hard origin 

Cuidado, porém, que isso é diferente de uma mesclagem real. Sua solução é provavelmente a opção que você está procurando.

Eu usei a resposta de Paul Pladijs desde agora. Eu descobri, você pode fazer uma fusão “normal”, os conflitos ocorrem, então você faz

 git checkout --theirs  

para resolver o conflito usando a revisão do outro ramo. Se você fizer isso para cada arquivo, terá o mesmo comportamento esperado

 git merge  -s theirs 

De qualquer forma, o esforço é mais do que seria com a estratégia de mesclagem! (Isso foi testado com a versão 1.8.0 do git)

Não está totalmente claro qual é o resultado desejado, por isso há alguma confusão sobre a maneira “correta” de fazê-lo nas respostas e nos seus comentários. Eu tento dar uma visão geral e vejo as três opções a seguir:

Tente mesclar e usar B para conflitos

Esta não é a “versão deles para git merge -s ours ” mas a “sua versão para git merge -X ours ” (que é a abreviação de git merge -s recursive -X ours ):

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

É isso que, por exemplo, a resposta de Alan W. Smith .

Use o conteúdo apenas de B

Isso cria uma consolidação de mesclagem para ambas as ramificações, mas descarta todas as alterações da branchA e mantém apenas o conteúdo da 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 

Observe que a mesclagem confirma primeiro pai agora é aquele do branchB e somente o segundo é do branchA . Isto é o que, por exemplo, a resposta de Gandalf458 .

Use o conteúdo de apenas B e mantenha a ordem dos pais correta

Este é o verdadeiro “deles versão para git merge -s ours “. Ele tem o mesmo conteúdo da opção anterior (isto é, somente do branchB ), mas a ordem dos pais é correta, ou seja, o primeiro pai vem do branchA e o segundo do 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 (ie content of branchB). git commit --amend -C HEAD 

Isso é o que a resposta de Paul Pladijs faz (sem exigir um ramo temporário).

Eu resolvi meu problema usando

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

Se você está no ramo A, faça:

 git merge -s recursive -X theirs B 

Testado na versão 1.7.8 do git

Ao mesclar o ramo de tópicos “B” em “A” usando o git merge, eu recebo alguns conflitos. Eu sei que todos os conflitos podem ser resolvidos usando a versão em “B”.

Estou ciente do git merge -s nosso. Mas o que eu quero é algo como git merge> -s deles.

Eu estou supondo que você criou um branch off master e agora quer se fundir de volta ao master, substituindo qualquer uma das coisas antigas no master. Isso é exatamente o que eu queria fazer quando me deparei com este post.

Faça exatamente o que você deseja fazer, exceto mesclar o primeiro ramo no outro primeiro. Eu fiz isso e funcionou muito bem.

 git checkout Branch git merge master -s ours 

Em seguida, faça o checkout master e mescle seu branch nele (tudo vai bem agora):

 git checkout master git merge Branch 

Para realmente fazer uma mesclagem que receba apenas a input do branch que você está mesclando, você pode fazer

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

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

git commit --amend

Não haverá conflitos em qualquer cenário que eu conheça, você não precisa fazer ramificações adicionais e ele age como um commit de mesclagem normal.

Isso não funciona bem com submodules no entanto.

Veja a resposta amplamente citada de Junio ​​Hamano : se você for descartar o conteúdo comprometido, apenas descarte os commits ou, de qualquer forma, mantenha-o fora do histórico principal. Por que incomodar todos no futuro lendo mensagens de commits que não têm nada a oferecer?

Mas às vezes há requisitos administrativos, ou talvez algum outro motivo. Para aquelas situações em que você realmente tem que gravar commits que não contribuem com nada, você quer:

(Edit: uau, eu consegui fazer isso errado antes. Este funciona.)

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

Este usa um comando git plumbing read-tree, mas contribui para um stream de trabalho geral mais curto.

 git checkout  git merge --no-commit -s ours  git read-tree -u --reset  git commit # Check your work! git diff  

Por que não existe?

Embora eu mencione no comando ” git para fazer um branch como outro ” como simular o git merge -s theirs , observe que o Git 2.15 (Q4 2017) agora está mais claro:

A documentação para ‘ -X ‘ para mesclagens foi escrita incorretamente para sugerir que ” -s theirs ” existe, o que não é o caso.

Veja commit c25d98b (25 set 2017) por Junio ​​C Hamano ( gitster ) .
(Mesclado por Junio ​​C Hamano – gitster – em commit 4da3e23 , 28 set 2017)

merge-strategies: evite implicar que ” -s theirs ” existe

A descrição da opção -Xours merge tem uma nota entre parênteses que diz aos leitores que é muito diferente de -s ours , o que é correto, mas a descrição de -Xtheirs que segue descuidadamente diz “isso é o oposto do ours “, dando uma falsa impressão de que os leitores também precisam ser avisados ​​de que é muito diferente de -s theirs , o que na realidade nem existe.

-Xtheirs é uma opção estratégica aplicada à estratégia recursiva. Isso significa que a estratégia recursiva ainda mesclará tudo o que puder, e só retornará à lógica ” theirs ” em caso de conflitos.

Esse debate sobre a pertinência ou não de uma estratégia de fusão theirs foi trazido de volta recentemente nesta discussão de setembro de 2017 .
Reconhece tópicos mais antigos (2008)

Em suma, a discussão anterior pode ser resumida para “nós não queremos ‘ -s theirs ‘, pois incentiva o stream de trabalho errado”.

Menciona o pseudônimo:

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

Yaroslav Halchenko tenta defender mais uma vez essa estratégia, mas Junio ​​C. Hamano acrescenta :

A razão pela qual a nossa e a deles não são simétricas é porque vocês são você e não eles – o controle e a propriedade de nossa história e sua história não são simétricas.

Uma vez que você decide que sua história é a linha principal, você prefere tratar sua linha de desenvolvimento como uma ramificação lateral e fazer uma mesclagem nessa direção, ou seja, o primeiro pai da mesclagem resultante é um commit em sua história e a segunda pai é o último mau da sua história. Então você acabaria usando ” checkout their-history && merge -s ours your-history ” para manter a primeira paternidade sensata.

E nesse ponto, o uso de ” -s ours ” não é mais uma solução alternativa para a falta de ” -s theirs “.
É uma parte apropriada da semântica desejada, ou seja, do ponto de vista da linha da história canônica sobrevivente, você quer preservar o que ela fez, anulando o que a outra linha da história fez .

Isso irá mesclar o seu newBranch em baseBranch existente

 git checkout  // this will checkout baseBranch git merge -s ours  // 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 

Eu acho que o que você realmente quer é:

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

Isso parece desajeitado, mas deve funcionar. O único pensamento que eu realmente não gosto sobre esta solução é que a história do git será confusa … Mas pelo menos o histórico será completamente preservado e você não precisará fazer algo especial para arquivos deletados.

ATUALIZAR

Enquanto a segunda resposta responde à pergunta original do OP, ela não reflete a intenção atualizada da pergunta do OP.


O que você está procurando não é o oposto do git merge -s ours comando que você está procurando o oposto do git merge -s recursive -X ours comando, que é git merge -s recursive -X theirs


Resposta Original

dado ramos originais

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

para mesclar o ramo B em A enquanto ignora o estado do ramo A, primeiro faça uma mesclagem regular

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

isto resulta em

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

não empurre essa mesclagem pois o ID de commit irá mudar (e está errado de qualquer forma) agora podemos mudar, depois do fato, a ours estratégia para a estratégia theirs

Não se esqueça de anotar o ID de consolidação da mesclagem, pois ela ficará indisponível após a próxima reboot a frio. (Se você esquecer nenhum dano será feito, mas você terá que fazer um hard reset de volta para A e começar tudo de novo).

 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) 

agora nós temos

 * 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 

feito

Eu precisava fazer isso quando um colega de trabalho aplicava minhas alterações A em sua ramificação independente B sem intercalar, isso me permite aceitar suas modificações na minha filial.

Recentemente, precisei fazer isso para dois repositorys separados que compartilham um histórico comum. Eu comecei com:

  • Org/repository1 master
  • Org/repository2 master

Eu queria que todas as mudanças do repository2 master fossem aplicadas ao repository1 master , aceitando todas as mudanças que o repository2 faria. Nos termos do git, esta deveria ser uma estratégia chamada -s theirs MAS não existe. Tenha cuidado, porque -X theirs é chamado como seria o que você quer, mas não é o mesmo (ele diz isso na página man).

A maneira como resolvi isso foi ir ao repository2 e fazer um novo branch repo1-merge . Nesse ramo, eu corri git pull git@gitlab.com:Org/repository1 -s ours e se funde bem sem problemas. Eu então empurro para o controle remoto.

Então eu volto para o repository1 e faço um novo branch repo2-merge . Nesse ramo, eu corro git pull git@gitlab.com:Org/repository2 repo1-merge que será concluído com problemas.

Finalmente, você precisaria emitir um pedido de mesclagem no repository1 para torná-lo o novo mestre ou apenas mantê-lo como uma ramificação.

O equivalente (que mantém a ordem pai) para ‘git merge -s theirs branchB’

Antes de mesclar: insira a descrição da imagem aqui

!!! Verifique se você está em estado limpo !!!

Faça a mesclagem:

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

O que fizemos ? Nós criamos um novo commit que dois pais são nossos e deles e o contnet do commit é branchB – deles

Após a mesclagem: insira a descrição da imagem aqui

Mais precisamente:

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