Como posso visualizar uma mesclagem no git?

397

Eu tenho um ramo git (a linha principal, por exemplo) e quero mesclar em outro ramo de desenvolvimento. Ou eu?

Para decidir se realmente quero mesclar esse ramo, gostaria de ver algum tipo de visualização do que a mesclagem fará. De preferência com a capacidade de ver a lista de confirmações que estão sendo aplicadas.

Até agora, o melhor que posso fazer é merge --no-ff --no-commite então diff HEAD.

Glenjamin
fonte
17
Eu gostaria git mergee git reset --keep HEAD@{1}se não gostar do resultado.
Jan Hudec
3
Observe que ver a lista de confirmações com suas diferenças não conta necessariamente a história toda - se a mesclagem não é trivial e, especialmente, se houver conflitos, o resultado real da mesclagem pode ser um pouco interessante.
quer
2
Seu método original faz exatamente isso. O ponto do meu comentário é que, embora analisar diferenças individuais seja muito bom, se você tiver uma mesclagem complexa, poderá obter resultados surpreendentes, mesmo que todos os commits mesclados sejam independentemente bons.
Cascabel
2
@ Jan: Por alguns motivos, git reset --keep HEAD@{1}retornou a fatal: Cannot do a keep reset in the middle of a merge.Ajuda?
27512
3
Por que não existe uma --previewopção no git-merge?
Gaui

Respostas:

285

Descobri que a solução que melhor funciona para mim é apenas executar a mesclagem e abortá-la se houver conflitos . Essa sintaxe específica parece limpa e simples para mim. Esta é a Estratégia 2 abaixo.

No entanto, se você deseja garantir que você não estrague sua ramificação atual ou simplesmente não está pronto para mesclar, independentemente da existência de conflitos, basta criar uma nova sub ramificação e mesclar isso:

Estratégia 1: A maneira segura - fundir um ramo temporário:

git checkout mybranch
git checkout -b mynew-temporary-branch
git merge some-other-branch

Dessa forma, você pode simplesmente jogar fora o ramo temporário se quiser apenas ver quais são os conflitos. Você não precisa se preocupar em "abortar" a mesclagem e pode voltar ao seu trabalho - basta fazer checkout de 'mybranch' novamente e você não terá nenhum código mesclado ou conflitos de mesclagem em sua ramificação.

Isso é basicamente um teste a seco.

Estratégia 2: quando você definitivamente deseja mesclar, mas apenas se não houver conflitos

git checkout mybranch
git merge some-other-branch

Se o git relatar conflitos (e SOMENTE SE EXISTIR conflitos), você poderá:

git merge --abort

Se a mesclagem for bem-sucedida, você não poderá abortá-la (somente redefinir).

Se você não estiver pronto para mesclar, use o caminho mais seguro acima.

[EDIT: 2016-Nov - Troquei a estratégia 1 por 2, porque parece que a maioria das pessoas está procurando "o caminho seguro". A estratégia 2 agora é mais uma observação de que você pode simplesmente interromper a mesclagem se a mesclagem tiver conflitos com os quais você não está pronto para lidar. Lembre-se de ler comentários!]

Kasapo
fonte
2
+1 para a estratégia 2. Ramificação temporária que mostra exatamente o que será inserido na mesclagem. A estratégia 1 é o que estou tentando evitar neste caso em particular.
27415 Gordolio
2
Sugiro mudar as estratégias para que a mais segura seja a primeira (meu treinamento psíquico está chegando - a maioria das pessoas presumiria que a melhor opção seria a primeira, apesar do uso claro da palavra "mais segura"), mas, além disso, excelente trabalho.
precisa
6
Você pode fazer um git merge --no-ff --no-commitse não desejar confirmar as alterações diretamente. Isso elimina a "necessidade" de uma ramificação diferente, facilitando um pouco a revisão das alterações.
Gerard van Helden
e se você decidir que não deseja mesclar nada e, de fato, preferir escrever um pouco mais de código e depois se comprometer com sua filial para poder implantar APENAS sua filial em um servidor de teste, você ainda não precisaria reverter o código git merge --no-ff --no-commit? Eu acho que você ainda pode fazer um git merge --abortdepois disso, se você não gosta do que vê? Mesmo que a mesclagem não produza conflitos?
Kasapo 19/07/16
A maioria das pessoas gosta de copiar e colar e não pensa muito. Portanto, para a Estratégia 1, talvez também adicione como interromper a mesclagem na ramificação local temporária git reset --hard HEADe faça check-out em uma ramificação diferente git checkout <different branch name>e exclua a ramificação temporária git delete -b <name of temporary branch>.
precisa saber é o seguinte
401
  • git log ..otherbranch
    • lista de alterações que serão mescladas na ramificação atual.
  • git diff ...otherbranch
    • diff do ancestral comum (base de mesclagem) para a cabeça do que será mesclado. Observe os três pontos , que têm um significado especial em comparação com dois pontos (veja abaixo).
  • gitk ...otherbranch
    • representação gráfica dos ramos desde que foram mesclados da última vez.

String vazia implica HEAD, é por isso que apenas em ..otherbranchvez de HEAD..otherbranch.

Os dois vs. três pontos têm um significado ligeiramente diferente para diff do que para os comandos que listam revisões (log, gitk etc.). Para log e outros, dois pontos ( a..b) significa tudo o que está dentro, bmas não ae três pontos ( a...b) significa tudo o que está em apenas um de aou b. Mas diff trabalha com duas revisões e, nesse caso, o caso mais simples representado por dois pontos ( a..b) é uma diferença simples de aaté be três pontos ( a...b) diferença média entre o ancestral comum e b( git diff $(git merge-base a b)..b).

Jan Hudec
fonte
7
O terceiro ponto foi a parte que estava faltando, obrigado! A abordagem log funciona bem também, log -p --reverse ..otherbranch parece ser uma boa maneira de ver o que seriam fundidas dentro.
Glenjamin
11
Eu estava desaparecido git checkout masterantes de tentar isso. Eu queria saber por que ele estava dizendo todas as minhas alterações foram vai ser sobre-escrito ...
Droogans
5
git show ..otherbranchmostrará uma lista de alterações e diferenças que serão mescladas na ramificação atual.
Gaui
4
Isso não é totalmente preciso, especialmente para palhetas de cereja.
precisa saber é o seguinte
2
@ void.pointer, o git não trata as escolhas de cereja especialmente na mesclagem normal, portanto também não é aqui. Uma estratégia de mesclagem poderia ser escrita, mas, até onde eu sei, nunca foi.
Jan Hudec
19

Se você é como eu, está procurando o equivalente a svn update -n. A seguir, parece fazer o truque. Observe que não se esqueça de fazer o git fetchprimeiro, para que seu repositório local tenha as atualizações apropriadas para comparação.

$ git fetch origin
$ git diff --name-status origin/master
D       TableAudit/Step0_DeleteOldFiles.sh
D       TableAudit/Step1_PopulateRawTableList.sh
A       manbuild/staff_companies.sql
M       update-all-slave-dbs.sh

ou se você quiser um diff da sua cabeça para o controle remoto:

$ git fetch origin
$ git diff origin/master

Na IMO, esta solução é muito mais fácil e menos propensa a erros (e, portanto, muito menos arriscada) do que a solução principal que propõe "mesclar e abortar".

djschny
fonte
11
deve ser $ git checkout target-branche depois $ git diff --name-status ...branch-to-be-merged(três pontos são essenciais para que digitá-los como é)
Lu55
Uma coisa está faltando: não mostra quais arquivos teriam um conflito - eles têm o mesmo marcador "M" que os arquivos que foram modificados na ramificação, mas podem ser mesclados sem nenhum conflito.
Peterflynn 07/10/19
Talvez as coisas tenham mudado em 2012, mas hoje em dia a interrupção de uma mesclagem parece bastante confiável, então não acho justo caracterizar isso como "muito mais fácil e menos propenso a erros" no momento.
David Z
8

A maioria das respostas aqui exige um diretório de trabalho limpo e várias etapas interativas (ruins para scripts), ou não funciona para todos os casos, por exemplo, mesclagens anteriores que já trazem algumas das alterações pendentes para o seu ramo de destino, ou escolhas mesmo.

Para realmente ver o que mudaria na masterramificação se você se unisse developa ela, agora:

git merge-tree $(git merge-base master develop) master develop

Como é um comando de encanamento, não adivinha o que você quer dizer, você precisa ser explícito. Também não coloriza a saída ou usa seu pager, portanto, o comando completo seria:

git merge-tree $(git merge-base master develop) master develop | colordiff | less -R

- https://git.seveas.net/previewing-a-merge-result.html

(obrigado a David Normington pelo link)

PS:

Se você obter conflitos de mesclagem, eles aparecerão com os marcadores de conflito usuais na saída, por exemplo:

$ git merge-tree $(git merge-base a b ) a b 
added in both
  our    100644 78981922613b2afb6025042ff6bd878ac1994e85 a
  their  100644 61780798228d17af2d34fce4cfbdf35556832472 a
@@ -1 +1,5 @@
+<<<<<<< .our
 a
+=======
+b
+>>>>>>> .their

O usuário @dreftymac faz uma boa observação: isso não é adequado para scripts, porque você não pode capturar isso facilmente a partir do código de status. Os marcadores de conflito podem ser bem diferentes, dependendo da circunstância (excluídos x modificados etc.), o que também dificulta o grep. Cuidado.

hraban
fonte
11
@hraban Parece a resposta correta, no entanto, aparentemente ainda há um elemento ausente. Essa abordagem exige que o usuário "olhe" a saída para ver se os marcadores de conflito estão presentes. Você tem uma abordagem que simplesmente retorna truese houver conflitos e falsese não houver conflitos (por exemplo, um valor booleano que não exija o teste do "globo ocular" ou qualquer intervenção humana).
precisa saber é o seguinte
11
@dreftymac não consegue encontrar nada nesse sentido. você pode usar algo como, git merge-tree ... | grep -q '^[a-z].*in both$' && echo conflict || echo safe to mergemas é finnicky; Provavelmente estou esquecendo um caso. talvez você queira verificar os marcadores de conflito? por exemplo, isso provavelmente não pega conflitos de estilo "deles excluídos, nossos alterados". (Acabei de verificar e que nem sequer mostrar marcadores de conflito, então você precisa de um regex meticulosa para ser seguro aqui)
Hraban
11
Use less -Rpara manipular saída colorida sem modificar sua configuração.
Giacomo Alzetta
Obrigado @GiacomoAlzetta, eu atualizei.
hraban 19/02
6

Se você já buscou as alterações, o meu favorito é:

git log ...@{u}

Isso precisa do git 1.7.x, no entanto, acredito. A @{u}notação é uma "abreviação" para o ramo upstream, por isso é um pouco mais versátil do que git log ...origin/master.

Nota: Se você usar o zsh e o glog estendido, provavelmente precisará fazer algo como:

git log ...@\{u\}
Pablo Olmos de Aguilera C.
fonte
6

Adicionando às respostas existentes, um alias pode ser criado para mostrar o diff e / ou log antes de uma mesclagem. Muitas respostas omitem o que fetchdeve ser feito antes de "visualizar" a mesclagem; este é um alias que combina essas duas etapas em uma (emulando algo semelhante ao mercurial's hg incoming/ outgoing)

Portanto, com base em " git log ..otherbranch", você pode adicionar o seguinte a ~/.gitconfig:

...
[alias]
    # fetch and show what would be merged (use option "-p" to see patch)
    incoming = "!git remote update -p; git log ..@{u}"

Para simetria, o alias a seguir pode ser usado para mostrar o que foi confirmado e seria enviado antes de ser enviado:

    # what would be pushed (currently committed)
    outgoing = log @{u}..

E então você pode executar " git incoming" para mostrar muitas alterações ou " git incoming -p" para mostrar o patch (ou seja, o "diff") " git incoming --pretty=oneline", para obter um resumo conciso, etc. Você pode (opcionalmente) executar " git pull" para realmente se fundem. (Embora você já tenha buscado, a mesclagem pode ser feita diretamente.)

Da mesma forma, " git outgoing" mostra o que seria enviado se você executasse " git push".

Michael
fonte
3

git log currentbranch..otherbranchfornecerá a lista de confirmações que entrarão na ramificação atual se você fizer uma mesclagem. Os argumentos usuais para registrar, que fornecem detalhes sobre as confirmações, fornecerão mais informações.

git diff currentbranch otherbranchlhe dará a diferença entre os dois commits que se tornarão um. Será um diff que fornece tudo o que será mesclado.

Isso ajudaria?

Noufal Ibrahim
fonte
2
Na verdade, errado. git log otherbranch..currentbranchfornece uma lista de confirmações no currentbranch . A git diff otherbranch currentbranchdá-lhe diff da versão a-ser-mesclado à ponta atual, que é quase tão inútil como pode ser, porque o que você quer é diff a partir da base de mesclagem para a cabeça de mesclagem.
Jan Hudec
Obrigado. Eu mudei os nomes das árvores.
Noufal Ibrahim
3

Solicitação de recebimento - usei a maioria das idéias já enviadas, mas uma que também uso com frequência é (especialmente se for de outro desenvolvedor) fazer uma solicitação de recebimento que fornece uma maneira útil de revisar todas as alterações em uma mesclagem antes que seja necessário Lugar, colocar. Eu sei que o GitHub não é o git, mas com certeza é útil.

G-Man
fonte
2

A menos que efetue a mesclagem de maneira descartável (consulte a resposta da Kasapo), não parece haver uma maneira confiável de ver isso.

Dito isto, aqui está um método que se aproxima marginalmente:

git log TARGET_BRANCH...SOURCE_BRANCH --cherry

Isso fornece uma indicação justa de quais confirmações entrarão na mesclagem. Para ver as diferenças, adicione -p. Para ver os nomes dos arquivos, adicionar qualquer um --raw, --stat, --name-only, --name-status.

O problema com a git diff TARGET_BRANCH...SOURCE_BRANCHabordagem (consulte a resposta de Jan Hudec) é que você verá diferenças nas alterações já no seu ramo de destino se o ramo de origem contiver mesclagens cruzadas.

Antak
fonte
1

Talvez isso possa te ajudar ? git-diff-tree - Compara o conteúdo e o modo dos blobs encontrados através de dois objetos em árvore

Chugaister
fonte
1

Não quero usar o comando git merge como precursor da revisão de arquivos conflitantes. Não quero fazer uma mesclagem, quero identificar problemas em potencial antes de mesclar - problemas que a mesclagem automática pode ocultar de mim. A solução que eu tenho procurado é como o git cospe uma lista de arquivos que foram alterados nos dois ramos que serão mesclados no futuro, em relação a algum ancestral comum. Depois de ter essa lista, posso usar outras ferramentas de comparação de arquivos para explorar ainda mais as coisas. Pesquisei várias vezes e ainda não encontrei o que desejo em um comando git nativo.

Aqui está minha solução alternativa, caso isso ajude outras pessoas por aí:

Nesse cenário, tenho um ramo chamado controle de qualidade que possui muitas alterações desde o último lançamento de produção. Nosso último lançamento de produção está marcado com "15.20.1". Eu tenho outro ramo de desenvolvimento chamado new_stuff que desejo mesclar no ramo de controle de qualidade. O controle de qualidade e o new_stuff apontam para confirmações que "seguem" (conforme relatado pelo gitk) a tag 15.20.1.

git checkout QA
git pull
git diff 15.20.1 --name-only > QA_files
git checkout new_stuff
git pull
git diff 15.20.1 --name-only > new_stuff_files
comm -12 QA_files new_stuff_files

Aqui estão algumas discussões sobre o motivo pelo qual estou interessado em segmentar esses arquivos específicos:

Como posso confiar na mesclagem do Git?

/software/199780/how-far-do-you-trust-automerge

Laura
fonte