Existe uma versão “deles” de “git merge -s ours”?
Pergunta
Ao mesclar o ramo de tópico "B" em "A" usando git merge
, recebo alguns conflitos.Eu sei que todos os conflitos podem ser resolvidos usando a versão em “B”.
Estou ciente git merge -s ours
.Mas o que eu quero é algo como git merge -s theirs
.
Por que isso não existe?Como posso obter o mesmo resultado após a fusão conflitante com o existente git
comandos?(git checkout
cada arquivo não mesclado de B)
ATUALIZAR:A "solução" de simplesmente descartar qualquer coisa do ramo A (o ponto de confirmação de mesclagem para a versão B da árvore) não é o que estou procurando.
Solução
Adicione o -X
opção para theirs
. Por exemplo:
git checkout branchA
git merge -X theirs branchB
Tudo vai se fundir da maneira desejada.
A única coisa que vi causar problemas é se os arquivos foram excluídos do Branchb. Eles aparecem como conflitos se algo diferente do Git fez a remoção.
A correção é fácil. Apenas corra git rm
com o nome de quaisquer arquivos que foram excluídos:
git rm {DELETED-FILE-NAME}
Depois disso, o -X theirs
deve funcionar como esperado.
Claro, fazendo a remoção real com o git rm
O comando impedirá que o conflito aconteça em primeiro lugar.
Observação: Uma opção de formulário mais longa também existe. Para usá -lo, substitua:
-X theirs
com:
--strategy-option=theirs
Outras dicas
Uma solução possível e testada para mesclar o ramo em nossa filial de 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 embrulhá -lo em um script usando BranchA e Branchb como argumentos.
Esta solução preserva o primeiro e o segundo pai do comprometimento da mesclagem, assim como seria de esperar git merge -s theirs branchB
.
Versões mais antigas do git permitiam que você usasse a estratégia de mesclagem "deles":
git pull --strategy=theirs remote_branch
Mas isso já foi removido, conforme explicado nesta mensagem por Júnio Hamano (o mantenedor do Git).Conforme observado no link, em vez disso você faria o seguinte:
git fetch origin
git reset --hard origin
Tenha cuidado, porém, pois isso é diferente de uma mesclagem real.Sua solução é provavelmente a opção que você realmente procura.
Eu usei a resposta de Paul Pladijs desde agora. Eu descobri, você pode fazer uma mesclagem "normal", conflitos ocorrem, então você faz
git checkout --theirs <file>
Para resolver o conflito usando a revisão do outro ramo. Se você fizer isso para cada arquivo, você terá o mesmo comportamento que seria de esperar de
git merge <branch> -s theirs
De qualquer forma, o esforço é mais do que seria com a estratégia de mesclagem! (Isso foi testado com o Git versão 1.8.0)
Não está totalmente claro qual é o resultado desejado, então há alguma confusão sobre a maneira "correta" de fazê -lo nas respostas e nos comentários deles. Eu tento dar uma visão geral e ver as três opções a seguir:
Tente mesclar e usar B para conflitos
Isto é não a "versão deles para git merge -s ours
"Mas a versão deles para git merge -X ours
"(o que é abrevido para git merge -s recursive -X ours
):
git checkout branchA
# also uses -s recursive implicitly
git merge -X theirs branchB
Isso é o que por exemplo ALAN W. Smith Resposta faz.
Use o conteúdo de B apenas
Isso cria um comprometimento de mesclagem para ambos os ramos, mas descarta todas as mudanças de branchA
e apenas mantém o conteúdo de 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 compromete o primeiro pai agora é o de branchB
e apenas o segundo é de branchA
. Isso é o que por exemplo Resposta de Gandalf458 faz.
Use o conteúdo apenas de B e mantenha a ordem dos pais correta
Esta é a verdadeira "versão deles para git merge -s ours
". Tem o mesmo conteúdo da opção antes (ou seja, apenas isso de branchB
) Mas a ordem dos pais está correta, ou seja, o primeiro pai vem de branchA
e o segundo de 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
Isso é o que 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ê estiver no ramo A:
git merge -s recursive -X theirs B
Testado no Git versão 1.7.8
Ao mesclar a ramificação do tópico "B" em "A" usando a mesclagem Git, recebo alguns conflitos. Eu sei que todos os conflitos podem ser resolvidos usando a versão em "B".
Estou ciente da mesclagem do git. Mas o que eu quero é algo como o Git mescle> -s deles.
Estou assumindo que você criou um ramo do mestre e agora quero voltar ao mestre, substituindo qualquer uma das coisas antigas do mestre. Foi exatamente isso que eu queria fazer quando me deparei com este post.
Faça exatamente o que você deseja fazer, exceto mesclar um ramo no outro primeiro. Eu apenas fiz isso, e funcionou muito bem.
git checkout Branch
git merge master -s ours
Em seguida, check -out mestre e mescle seu ramo nela (vai correr bem agora):
git checkout master
git merge Branch
Para realmente fazer uma mesclagem que leva só Entrada do ramo que você está se fundindo, 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 nenhum cenário que eu conheça, você não precisa fazer ramos adicionais e age como um comprometimento normal de mesclagem.
Isso não é bom com submódulos, no entanto.
Ver Resposta amplamente citada de Junio Hamano:se você for descartar o conteúdo confirmado, 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 existem requisitos administrativos, ou talvez por algum outro motivo.Para aquelas situações em que você realmente precisa registrar commits que não contribuem em nada, você deseja:
(editar:uau, eu consegui errar antes.Este funciona.)
git update-ref HEAD $(
git commit-tree -m 'completely superseding with branchB content' \
-p HEAD -p branchB branchB:
)
git reset --hard
Por que isso não existe?
Embora eu mencione em "Comando git para fazer um branch igual a outro"como simular git merge -s theirs
, observe que o Git 2.15 (quarto trimestre de 2017) agora está mais claro:
A documentação para '
-X<option>
'Pois fusão foi enganosamente escrito para sugerir que "-s theirs
" existe, o que não é o caso.
Ver confirmar c25d98b (25 de setembro de 2017) por Júnio C Hamano (gitster
).
(Mesclado por Júnio C Hamano-- gitster
-- em confirmar 4da3e23, 28 de setembro de 2017)
estratégias de mesclagem:evite insinuar que "
-s theirs
" existeA descrição de
-Xours
a opção de mesclagem tem uma nota entre parênteses que diz aos leitores que é muito diferente de-s ours
, que é correto, mas a descrição de-Xtheirs
que segue -o descuidadamente diz "este é o oposto deours
", dando uma falsa impressão de que os leitores também precisam ser avisados de que é muito diferente de-s theirs
, que na realidade nem existe.
-Xtheirs
é um opção de estratégia aplicado à estratégia recursiva.Isso significa que a estratégia recursiva ainda mesclará tudo o que puder e retornará apenas para "theirs
"lógica em caso de conflitos.
Esse debate sobre a pertinência ou não de uma theirs
estratégia de fusão foi trazida de volta recentemente neste setembro.Tópico de 2017.
Ele reconhece tópicos mais antigos (2008)
Em suma, a discussão anterior pode ser resumida em "não queremos"
-s theirs
', pois incentiva o fluxo de trabalho errado".
Ele menciona o apelido:
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 Júnio C.Hamano acrescenta:
A razão pela qual a nossa e a deles não são simétricas é porque você é você e não eles – o controle e a propriedade de nossa história e da história deles não são simétricos.
Depois de decidir que a história deles é a linha principal, você prefere tratar sua linha de desenvolvimento como um ramo secundário e fazer uma fusão nessa direção, ou seja,o primeiro pai da mesclagem resultante é um commit em seu histórico e o segundo pai é o último pai ruim do seu histórico.Então você acabaria usando "
checkout their-history && merge -s ours your-history
"Para manter a primeira parentidade sensata.E nesse ponto, o uso de "
-s ours
"não é mais uma solução alternativa por falta de"-s theirs
".
É uma parte adequada da semântica desejada, ou seja,do ponto de vista da linha histórica canônica sobrevivente, você quer preservar o que ela fez, anulando o que a outra linha da história fez.
Este usa uma leitura de comando de encanamento Git, mas cria um fluxo de trabalho geral mais curto.
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>
Isso vai mesclar seu newbranch no BaseBranch existente
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
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 dessa solução é que o histórico do Git será confuso ... mas pelo menos a história será completamente preservada e você não precisará fazer algo especial para arquivos excluídos.
O equivalente (que mantém a ordem dos pais) para 'Git mesclar -s deles Branchb'
!!! Certifique -se de que 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 ? Criamos um novo compromisso que dois pais nossos e deles e o contador da confirmação são Branchb - deles
Mais precisamente:
git commit-tree -m "take theirs" -p HEAD -p 'SOURCE^{commit}' 'SOURCE^{tree}'
Esta resposta foi dada por Paul Pladijs. Acabei de receber seus comandos e fiz um pseudônimo de git por conveniência.
Edite seu .GitConfig e adicione o seguinte:
[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"
Então você pode "Git mescle -s deles a" executando:
git checkout B (optional, just making sure we're on branch B)
git mergetheirs A
Recentemente, eu precisava fazer isso para dois repositórios separados que compartilham uma história comum. Comecei com:
Org/repository1 master
Org/repository2 master
Eu queria todas as mudanças de repository2 master
a ser aplicado a repository1 master
, aceitar todas as mudanças que o repositório2 faria. Em termos de Git, este deve ser uma estratégia chamada -s theirs
Mas não existe. Tenha cuidado porque -X theirs
é nomeado como seria o que você quer, mas é NÃO o mesmo (até diz isso na página do homem).
A maneira como eu resolvi isso era ir para repository2
e fazer um novo ramo repo1-merge
. Naquele 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 repository1
e fazer um novo ramo 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 uma solicitação de mesclagem em repository1
Para torná -lo o novo mestre, ou apenas mantê -lo como um ramo.
Uma maneira simples e intuitiva (na minha opinião) de duas etapas é
git checkout branchB .
git commit -m "Picked up the content from branchB"
Seguido por
git merge -s ours branchB
(que marca os dois ramos como mesclados)
A única desvantagem é que ele não remove arquivos que foram excluídos no Branchb da sua ramificação atual. Uma diferença simples entre as duas ramificações depois mostrará se houver desses arquivos.
Essa abordagem também deixa claro o registro de revisão depois do que foi feito - e o que se destinava.