Git: encontre o ancestral comum mais recente de dois ramos

844

Como encontrar o ancestral comum mais recente de dois ramos do Git?

Ted
fonte
3
Definir mais recente: hora do mundo real, número de confirmações, outra métrica?
Ciro Santilli escreveu
2
Relevante (mesclagens cruzadas): stackoverflow.com/questions/26370185/…
jub0bs
1
@CiroSantilli 中心 改造 中心 996ICU 六四 é o mesmo em qualquer métrica, não é?
YakovL
@YakovL Acredito que não por causa da ramificação e porque você pode definir datas de confirmação arbitrárias em seus objetos de confirmação: essa data provavelmente não é a que você deseja.
Ciro Santilli foi lançado em 19/05/19
1
@CiroSantilli 中心 改造 中心 996ICU 六四 seems parece-me que só pode ser diferente se antes do último commit comum na árvore houver um commit com um timestamp mais antigo. Você pode fornecer um exemplo menos trivial?
YakovL

Respostas:

1019

Você está procurando git merge-base. Uso:

$ git merge-base branch2 branch3
050dc022f3a65bdc78d97e2b1ac9b595a924c3f2
CB Bailey
fonte
85
Observe que este encontra o ancestral comum mais recente ... que eu acredito que é o que o questionador deseja, então +1. Apenas observando, no caso de alguém vir aqui tentando encontrar o ancestral comum mais antigo (como eu fiz) - para o qual, veja também: stackoverflow.com/questions/1527234/…
lindes
16
@funroll: Ou a abreviação para isso:git log master...HEAD
CB Bailey
17
@lindes o ancestral comum mais antigo não seria o commit inicial?
Thorbjørn Ravn Andersen
8
@ ThorbjørnRavnAndersen, sim, eu suponho que seja assim ... A dificuldade na descrição vem do fato de o git usar um Gráfico Acíclico Dirigido, e ainda assim ser visto como uma árvore, o que tecnicamente não é. Para ter mais cuidado com minha redação, eu estava falando sobre o caso em que você deseja que o pai da primeira instância dos "ramos" seja divergente ... uma vez que eles podem ter vários pontos nos quais foram re-mesclados e re-divididos, isto é o "mais antigo" deles, mas não o ancestral mais antigo, que é (eu acho) sempre o commit inicial.
Lindes
5
Embora essa pergunta seja estritamente sobre encontrar um ancestral comum de dois ramos, qualquer pessoa que queira o ancestral comum de três ou mais ramos deve observar que precisa passar a --octopusbandeira para obter o resultado certo. O óbvio, mas errado git merge-base branch1 branch2 branch3, fornecerá uma confirmação, mas, conforme descrito na seção Discussão nos documentos, não é necessariamente um ancestral comum dos três ramos.
Mark Amery
46

git diff master...feature

mostra todos os novos commit do seu ramo de recurso atual (possivelmente com vários commit).

man git-diff documentos que:

git diff A...B

é o mesmo que:

git diff $(git merge-base A B) B

mas ...é mais fácil digitar e lembrar.

Conforme mencionado por Dave , o caso especial de HEADpode ser omitido. Assim:

git diff master...HEAD

é o mesmo que:

git diff master...

o que é suficiente se o ramo atual for feature.

Finalmente, lembre-se de que a ordem é importante! Doing git diff feature...mastermostrará alterações que masternão estão ativadas feature.

Eu gostaria que mais comandos git suportassem essa sintaxe, mas acho que não. E alguns até têm semânticas diferentes para ...: Quais são as diferenças entre o ponto duplo ".." e o ponto triplo "..." nos intervalos de confirmação do Git?

Ciro Santilli adicionou uma nova foto
fonte
8
Ou apenas git diff master...no caso especial de diferir paraHEAD
Dave
o "..." não funcionou para mim no powershell, engraçado funcionou no console git talvez o repo não tenha sido concluído, git diff $ (base de mesclagem git AB) B funcionou e já que eu sou um pouco novo no git Eu estava um pouco cético de que isso pode mesclar os ramos :)
Moiz Ahmed
1
Uau. bastante surpreendente. e se o ramo que você deseja não existe no seu repositório local porque você nunca efetuou o check-out, você pode simplesmente fazê-lo.git diff origin/branchname...
Mark Ch
25

Como observado em uma resposta anterior, git merge-basefunciona:

$ git merge-base myfeature develop
050dc022f3a65bdc78d97e2b1ac9b595a924c3f2

mas se myfeatureé o ramo atual, como é comum, você pode usar use --fork-point:

$ git merge-base --fork-point develop
050dc022f3a65bdc78d97e2b1ac9b595a924c3f2

Este argumento funciona apenas em versões suficientemente recentes do git. Infelizmente, nem sempre funciona, no entanto, e não está claro o porquê. Por favor, consulte as limitações observadas no final desta resposta .


Para informações completas sobre confirmação, considere:

$ git log -1 $(git merge-base --fork-point develop) 
Acumenus
fonte
Eu tenho git version 2.14.1.windows.1. A execução git merge-base --fork-point branch2com uma ramificação (com seus próprios commits) que eu sei que foi bifurcada na ramificação atual não produz nenhum resultado, enquanto git merge-base branch1 branch2mostra corretamente o ponto de bifurcação. Qual poderia ser o problema?
ADTC
@ADTC Checkout branch2e, em seguida, execute git merge-base --fork-point branch1.
Acumenos
@ADTC Use um visualizador gráfico de confirmação, por exemplo gitk, etc. para ver como é a árvore. Talvez você obtenha sua resposta.
Acumenus 21/10
Não vejo nada de estranho na árvore quando a vejo graficamente. Eu posso rastrear os caminhos e encontrar o ancestral comum que corresponde ao resultado de git merge-base branch1 branch2. Mas o estranho é que isso --fork-pointnão dá nada de qualquer maneira. Você confirmou que funciona para você como pretendido?
ADTC
1
Eu recebo o mesmo que @ADTC. O comando 'git log -1 $ (git merge-base --fork-point anotherBranch)' não mostra nenhum resultado usando a versão 2.16.2.windows.1 do git.
masinger
10

Com gitkvocê pode visualizar os dois ramos graficamente:

gitk branch1 branch2

E então é fácil encontrar o ancestral comum na história dos dois ramos.

Martin G
fonte
6
Nem tudo pode ser feito visualmente em todos os casos. Existem razões pelas quais as coisas podem precisar ser automatizadas programaticamente.
ADTC