Existe uma opção git-merge --dry-run?

725

Estou me fundindo em um ramo remoto que pode ter muitos conflitos. Como posso saber se haverá conflitos ou não?

Eu não vejo nada como um --dry-runon git-merge.

Otto
fonte
5
Como a ramificação é barata com o Git, por que não fazer check-out de uma cópia e não precisar executar uma execução a seco? Você pode simplesmente jogar fora a cópia depois.
Alexander Mills

Respostas:

812

Como observado anteriormente, passe o --no-commitsinalizador, mas para evitar um commit de avanço rápido, também passe --no-ffo seguinte:

$ git merge --no-commit --no-ff $BRANCH

Para examinar as alterações faseadas:

$ git diff --cached

E você pode desfazer a mesclagem, mesmo que seja uma mesclagem de avanço rápido:

$ git merge --abort
mipadi
fonte
51
Isso é ótimo, mas ainda modifica sua cópia de trabalho. Se o seu repo é um servidor web ao vivo, então você poderia estar servindo arquivos com conflitos.
dave1010
21
Você não pode realmente fazer uma mesclagem sem afetar a cópia de trabalho.
mipadi
55
É verdade, mas algo como git merge --only-if-there-wont-be-any-conflictsou git diff --show-conflicts <commit>seria realmente útil. Pena que ainda não é possível, ou estou perdendo alguma coisa?
Dave1010
344
@ dave1010 Você nunca deve manipular fusões em um servidor da web ao vivo !!! É para isso que serve a sua caixa de desenvolvimento! Corrija o ramo "prod" e empurre-o para o servidor da web real.
Jspwain # 1
52
Se você trabalha em um servidor ativo / de produção, nunca mais quer fazer nada git pull --ff-only!
ThiefMaster 14/03/12
237

Eu apenas tive que implementar um método que encontre automaticamente conflitos entre um repositório e seu controle remoto. Essa solução mescla a memória para não tocar no índice nem na árvore de trabalho. Penso que esta é a forma mais segura possível de resolver este problema. Veja como funciona:

  1. Busque o controle remoto no seu repositório. Por exemplo: git fetch origin master
  2. Execute git merge-base: git merge-base FETCH_HEAD master
  3. Execute a árvore de mesclagem git: git merge-tree mergebase master FETCH_HEAD(a base de fusão é o ID hexadecimal que a base de mesclagem imprimiu na etapa anterior)

Agora, suponha que você queira mesclar o mestre remoto com o mestre local, mas você pode usar quaisquer ramificações. git merge-treeexecutará a mesclagem na memória e imprimirá o resultado na saída padrão. Grep para o padrão <<ou >>. Ou você pode imprimir a saída em um arquivo e verificar isso. Se você encontrar uma linha que começa com 'alterado em ambos', provavelmente haverá um conflito.

akostajti
fonte
41
Esta resposta é muito subestimada, IMHO, pois é uma solução limpa sem tocar na cópia de trabalho ou no índice.
31512 ssssububerth
23
BTW, os passos 2 e 3 podem ser fundidos em uma única etapa, usando o operador de crase de console Linux, que avalia no local seu conteúdo:git merge-tree `git merge-base FETCH_HEAD master` FETCH_HEAD master
jakub.g
15
Adicione ao [alias] no .gitconfig: dry = "! F () {git merge-tree` git merge-base $ 2 $ 1` $ 2 $ 1;}; f "#check como a fusão do dev no master irá: dev master
Noel
8
Minha nova linha fav GIT: git merge-tree `git merge-base clieop master` clieop master | grep -A3 "changed in both"Simplesmente incrível! +100
Rudie
4
Ao testar isso, achei grepping para mesclagens de sinalizadores 'alterado em ambos', onde os dois ramos modificam o mesmo arquivo, mesmo que não resultem em um conflito de mesclagem. Para identificar apenas conflitos reais, achei necessário grep para a marcação de conflito que começa assim:, +<<<<<<< .ourentão eu uso uma expressão grep comogrep -q '^+<* \.our$'
Guy
55

Minha solução simples de força bruta para isso é:

  1. Crie uma ramificação "pré-mestre" (do mestre, é claro)

  2. Mesclar todas as coisas que você deseja neste pré-mestre.
    Então você pode ver como a fusão aconteceu sem tocar no mestre.

    • Mesclar o pré-mestre no mestre OU
    • Mesclar todas as ramificações liberadas por aspirantes a mestre

Enfim, eu seguiria o conselho da @ orange80.

hades
fonte
5
Gosto da solução @akostajti, mas essa é mais uma opção subestimada. Na verdade, prefiro ficar na defensiva e criar um novo ramo temporário (é claro que apenas quando espero conflitos, caso contrário, será um exagero) e, se algo der errado, exclua-o.
Jkub.g
1
não sei se esta é uma solução "suja" ou não, mas realmente funciona. Eu gosto disso! (Y)
sara
3
Essa deve ser a solução aceita, imo. É rápido, fácil, seguro, reversível, intuitivo e, desde que não haja alterações não confirmadas antes de começar, não haverá efeitos colaterais.
Bob Ray
3
Esta solução indica que você não entende como o git funciona. Ramificação são apenas ponteiros e você está apenas criando um ponteiro redundante. Você tem um mau pressentimento de que, de alguma forma, pode prejudicar sua fusão de ramo, mas não pode. Você sempre pode fazer git merge --abortse houver conflitos, git reset --hard HEAD~1se houve uma mesclagem ou git reset --hard origin/master. Criar outro ramo dá a você uma sensação de segurança, mas se você aprender como o git funciona, entenderá que é um medo equivocado. Quando se trata de não alterar a cópia de trabalho, isso não oferece solução.
Thibault D.
@ thibault-d Pense em quão complexa é a solução quando você não inicia com uma ramificação limpa. git merge --no-commitnão abortará uma mesclagem se puder ser encaminhada rapidamente. git merge --abortnão funciona se foi mesclado. Se você deseja escrever isso como um script, é estranho, pois git mergenão responde com códigos de erro suficientes para explicar os diferentes tipos de conflitos. Trabalhar com uma ramificação nova impede que um script quebrado deixe seu repositório em um estado que exija intervenção manual. Claro que você não pode perder nada. Mas é mais fácil construir de outra maneira.
Erik Aronesty 17/10/19
47

Desfazer uma mesclagem com o git é tão fácil que você nem precisa se preocupar com a execução a seco:

$ git pull $REMOTE $BRANCH
# uh oh, that wasn't right
$ git reset --hard ORIG_HEAD
# all is right with the world

EDIT: Como observado nos comentários abaixo, se você tiver alterações no diretório de trabalho ou na área de armazenamento temporário, provavelmente desejará armazená-las antes de fazer o procedimento acima (caso contrário, elas desaparecerão após o procedimento git resetacima)

Brian Phillips
fonte
7
Basta verificar se um merge será fast-forward (FF) é uma questão de verificar a lista de git branch --contains HEADou até mesmo mais diretamente, o uso apenasgit merge --ff-only
Brian Phillips
7
git reset --hard é um dos poucos comandos de exclusão de informações sem backout que o git possui, portanto, deve ser usado com extrema cautela. Como tal, -1
Kzqai 22/02/12
8
@Tchalvak ainda há reflog.
Kissaki 17/05
3
--dry-runnão "simplesmente verifica se uma mesclagem será rápida". Ele retornaria a saída exata que uma mesclagem faria: arquivos, conflitos etc. Se will will ff não é realmente interessante, é?
22412 Rudie
3
que tal git stash; git reset --hard? @BrianPhillips
Code Whisperer
41

Fiz um alias para fazer isso e funciona como um encanto, faço o seguinte:

 git config --global alias.mergetest '!f(){ git merge --no-commit --no-ff "$1"; git merge --abort; echo "Merge aborted"; };f '

Agora eu só ligo

git mergetest <branchname>

Para descobrir se há algum conflito.

Okonomiyaki3000
fonte
Brilhante! Eu estou mantendo isso.
qbert65536
28

Apenas diferencie sua ramificação atual em relação à ramificação remota, isso informará o que será alterado quando você fizer uma extração / mesclagem.

#see diff between current master and remote branch
git diff master origin/master
timh
fonte
1
Idéia interessante. Como eu examinaria essa saída e determinaria se a mesclagem funcionaria ou não?
precisa saber é o seguinte
6
Isso não informa se ocorrerá algum conflito ... mas fornecerá uma idéia geral do que acontecerá se você fizer uma extração / fusão.
timh
10
Isso indicará apenas a diferença entre os dois ramos, não informará qual será o resultado da mesclagem. Essa é uma distinção importante, pois, em alguns casos, a mesclagem automaticamente aceita alterações de diferentes ramificações, dependendo de quando elas foram confirmadas. Portanto, em essência, fazer um diff pode fazer você pensar que algumas de suas alterações serão revertidas quando, na realidade, o processo de mesclagem aceitará automaticamente as alterações mais recentes que as anteriores. Espero que isso faça sentido.
markquezada
3
Para desenvolver o comentário do @ mirthlab, haverá uma diferença significativa entre diff e mesclagem se alguém já tiver realizado uma mesclagem com a estratégia de mesclagem "our" (ou alguns outros consertos manuais de mesclagem); o diff também mostrará diferenças que já são contadas como "mescladas".
Tao
21

Eu uso o comando request-pull git para fazer isso. Ele permite que você veja todas as alterações que aconteceriam durante a mesclagem, mas sem fazer nada em seus repositórios locais ou remotos .

Por exemplo, imagine que você deseja mesclar um ramo chamado "feature-x" em seu ramo mestre

git request-pull master origin feature-x

mostrará um resumo do que aconteceria (sem fazer nada):

The following changes since commit fc01dde318:
    Layout updates (2015-06-25 11:00:47 +0200)
are available in the git repository at:
    http://fakeurl.com/myrepo.git/ feature-x
for you to fetch changes up to 841d3b41ad:
----------------------------------------------------------------
john (2):
    Adding some layout
    Refactoring
ioserver.js            |   8 +++---
package.json           |   7 +++++-
server.js              |   4 +--
layout/ldkdsd.js       | 277 +++++++++++++++++++++++++++++++++++++
4 files changed, 289 insertions(+), 7 deletions(-)
create mode 100644 layout/ldkdsd.js

Se você adicionar o -pparâmetro, também receberá o texto completo do patch, exatamente como se estivesse fazendo um diff git em cada arquivo alterado.

ArnaudR
fonte
3
Você poderia fazer isso um pouco mais clara, adicionando que mastere originfazer nas opções de linha de comando, e que sobre se estou, por exemplo, a nível local branch1e quer fazer um request-pullem um ramo de funcionalidade locais branch2? Eu ainda preciso origin? Claro, sempre se pode ler a documentação.
Ela782
Infelizmente esse comando só funciona se Rev # 2 for um nome de filial, não funciona para hashes: /
Jared Grubb
20

Estou surpreso que ninguém tenha sugerido o uso de patches ainda.

Digamos que você gostaria de testar uma mesclagem de your_branchdentro master(eu estou supondo que você tenha mastercheck-out):

$ git diff master your_branch > your_branch.patch
$ git apply --check your_branch.patch
$ rm your_branch.patch

Isso deve fazer o truque.

Se você receber erros como

error: patch failed: test.txt:1
error: test.txt: patch does not apply

isso significa que o patch não foi bem-sucedido e uma fusão produziria conflitos. Nenhuma saída significa que o patch está limpo e você poderá mesclar facilmente a ramificação


Observe que isso realmente não altera sua árvore de trabalho (além de criar o arquivo de correção, é claro, mas você pode excluí-lo com segurança depois). Na documentação do git-apply:

--check
    Instead of applying the patch, see if the patch is applicable to the
    current working tree and/or the index file and detects errors. Turns
    off "apply".

Observe para quem é mais esperto / mais experiente com o git do que eu: informe-me se eu estiver errado aqui e esse método mostra um comportamento diferente do que uma mesclagem regular. Parece estranho que, nos mais de 8 anos em que essa pergunta existisse, ninguém sugerisse essa solução aparentemente óbvia.

Christoph Böhmwalder
fonte
Este método é a resposta aceita para esta pergunta e existem algumas ressalvas nos comentários, como "o git não foi capaz de usar a estratégia de mesclagem 'recursiva'" e "o arquivo de correção gera erro para novos arquivos". Caso contrário, parece ótimo.
N /
1
Um caminho mais curto, sem criar um arquivo de patch temporário: git diff master your_branch | git apply --check.
ks1322
9

Isso pode ser interessante: Na documentação:

Se você tentou uma mesclagem que resultou em conflitos complexos e deseja recomeçar, é possível recuperar com o git merge --abort .

Mas você também pode fazê-lo da maneira ingênua (mas lenta):

rm -Rf /tmp/repository
cp -r repository /tmp/
cd /tmp/repository
git merge ...
...if successful, do the real merge. :)

(Nota: não funcionará apenas na clonagem em / tmp, você precisará de uma cópia para garantir que as alterações não confirmadas não entrem em conflito).


fonte
2
Se tudo o que você precisa é de um martelo ... :) +1
kaiser
Cópia limpa pode ser obtida com cp -r repository/.git /tmp/repository/.git, cd /tmp/repository, git reset --hard, git add --all, git reset --hard(para uma boa medida), git status(para verificar se ele está limpo).
ADTC
8

Estou ciente de que essa é uma pergunta antiga, mas é a primeira a aparecer em uma pesquisa no Google.

O Git introduziu uma opção --ff-only ao mesclar.

From: http://git-scm.com/docs/git-merge


--ff-only

Recuse-se a mesclar e sair com um status diferente de zero, a menos que o HEAD atual já esteja atualizado ou a mesclagem possa ser resolvida como um avanço rápido.

Fazer isso tentará mesclar e avançar rapidamente e, se não puder, interrompe e solicita que o avanço rápido não possa ser executado, mas deixa o ramo de trabalho intocado. Se puder avançar rapidamente, executará a mesclagem em sua ramificação de trabalho. Esta opção também está disponível em git pull. Assim, você pode fazer o seguinte:

git pull --ff-only origin branchA #See if you can pull down and merge branchA

git merge --ff-only branchA branchB #See if you can merge branchA into branchB
Jason McKindly
fonte
1
Isso fará a mesclagem se puder ser feito com avanço rápido, que não é o que eu queria na pergunta original. Eu acho que a resposta aceita tem a outra metade que a corrige.
Otto
Realmente, porém, as solicitações extravagantes do Git evitam a necessidade que eu tenho desse tipo de coisa.
Otto
2
Não é realmente o mesmo. Sair com status diferente de zero porque a mesclagem não pode ser resolvida, pois o avanço rápido não significa que há conflitos . Significa apenas que o histórico divergiu e é necessário um commit de mesclagem.
ADTC
7

Eu uso o git log para ver o que mudou em um ramo de recurso do ramo mestre

git log does_this_branch..contain_this_branch_changes

por exemplo - para ver quais confirmações estão em um ramo de recurso que / não foi mesclado ao mestre:

git log master..feature_branch
Nelsonelson
fonte
3

Se você quiser avançar de B para A, certifique-se de que o git log B..A não mostre nada, ou seja, A não possui nada que B não possua. Mas mesmo que B..A possua alguma coisa, você ainda poderá mesclar sem conflitos, portanto, o acima mostra duas coisas: haverá um avanço rápido e, portanto, você não terá um conflito.

Erik Kaplun
fonte
2

Minha solução é mesclar para trás.

Em vez de mesclar sua ramificação na ramificação "alvo" remota, mesclar essa ramificação na sua.

git checkout my-branch
git merge origin/target-branch

Você verá se há algum conflito e pode planejar como resolvê-lo.

Depois disso, você pode interromper a mesclagem via git merge --abortou (se não houver nenhum conflito e mesclagem) reverter para a consolidação anterior viagit reset --hard HEAD~1

Ubeogesh
fonte
-2

Faça uma cópia temporária da sua cópia de trabalho, mescle-a e difira as duas.

vanboom
fonte