Usando o Git, mostre todos os commits que estão em um ramo, mas não no (s) outro (s)

465

Eu tenho um ramo antigo que gostaria de excluir. No entanto, antes de fazer isso, quero verificar se todas as confirmações feitas neste ramo foram em algum momento mescladas em outro ramo. Portanto, gostaria de ver todos os commits feitos no meu branch atual que não foram aplicados a nenhum outro branch [ou, se isso não for possível sem algum script, como é possível ver todos os commits em um branch que não foram aplicados para outro ramo?].

sircolinton
fonte
Para listar commits perdidos entre dois ramos você pode usar compare-branches.py bitbucket.org/aakef/compare-git-branches
Bernd Schubert
Relacionados: stackoverflow.com/q/1419623/1959808
Ioannis Filippidis

Respostas:

321

Você provavelmente só quer

git branch --contains branch-to-delete

Isso listará todas as ramificações que contêm as confirmações de "ramificação para exclusão". Se ele relatar mais do que apenas "ramificar para excluir", a ramificação foi mesclada.

Suas alternativas são realmente apenas coisas de sintaxe de lista de revenda. por exemplo, git log one-branch..another-branchmostra tudo o que one-branchprecisa ter tudo o que another-branchtem.

Você também pode estar interessado em git show-branchuma maneira de ver o que há onde.

Dustin
fonte
2
+1. Veja também stackoverflow.com/questions/850607/…
VonC 10/11/2009
1
A linha 'Se relatar algo, a ramificação foi mesclada' pode ser mal interpretada: se git branch --contains some-branchapenas retornar some-branch, ela retornará algo, mas não foi mesclada.
Confusão
5
Observe que git log foo..barmostrará os commits entre os mais recentes do bar e os mais recentes do foo, mas nenhum outro commit ausente ainda mais no tempo. Para ver tudo no bar, mas não no foo, você deve usar a solução do @ jimmyorr.
Paul A Jungwirth
556

Para ver uma lista de quais confirmações estão em uma ramificação, mas não em outra, use o git log:

git log --no-merges oldbranch ^newbranch

... ou seja, mostre logs de confirmação para todos os commit no oldbranch que são não no newbranch. Você pode listar várias ramificações para incluir e excluir, por exemplo

git log  --no-merges oldbranch1 oldbranch2 ^newbranch1 ^newbranch2

Nota: no Windows ^é uma chave de escape, portanto, ele precisa ser escapado com outra ^:

git log --no-merges oldbranch ^^newbranch
jimmyorr
fonte
2
Eu encontrei procurando git compare commits de dois ramos.
Utilizador
25
Era exatamente isso que eu estava procurando. Mas, usar ^como prefixo aqui me confundiu. Nesse contexto, significa excluir esse ramo. Usar ^como sufixo seria uma referência relativa ao commit pai desse ramo.
21813 Joe Flynn
4
muito útil obrigado. Estou curioso, por que a bandeira --no-merges é necessária? Certamente alguém quer ver esses commits também?
precisa
2
Gostaria de usar o gitk com isso? Basta usar gitk oldbranch ^newbranch --no-merges(Testado com git 1.8.1.1). Nota lateral, para mim ^significa inclusivo HEAD commit do branch newbranch.
Matt
2
@NazariiGudzovatyi - sim, existe: "-cherry-pick". Há um número enorme de opções para log na página de documentação
romeara
91

Para mostrar os commits em oldbranch, mas não em newbranch:

git log newbranch..oldbranch

Para mostrar o diff por esses commits (observe que há três pontos):

git diff newbranch...oldbranch

Aqui está o documento com uma ilustração do diagrama https://git-scm.com/book/en/v2/Git-Tools-Revision-Selection#Commit-Ranges

Xuan
fonte
Veja o comentário de Paul A Jungwirth acima. Parece que isso vai perder alguns commits antigos?
Variável miserável
2
Não tenho certeza do que idade significa. Os pontos duplos basicamente pedem ao Git que resolva um intervalo de confirmações acessíveis a partir de uma confirmação, mas não acessíveis a partir de outra. Aqui está o documento com uma ilustração do digram git-scm.com/book/en/v2/…
Xuan
1
e se estamos em ambos newbranchou oldbranch, o que podemos fazer git log ..oldbranchou git log newbranch.., respectivamente
YakovL
A solução de jimmyorr não funcionou para mim, mas esta funcionou graças aos dois pontos ..entre os nomes dos árbitros. Também usei a --cherry-pickopção para ocultar confirmações que estão presentes nos dois ramos, mas que têm um hash diferente porque foram escolhidas de um ramo para o outro.
flawyte
58

Para aqueles que ainda procuram uma resposta simples, confira git cherry . Ele compara diffs reais em vez de confirmar hashes. Isso significa que ele acomoda confirmações que foram escolhidas ou refazidas com cereja.

Primeiro faça o checkout do ramo que você deseja excluir:

git checkout [branch-to-delete]

então use git cherry para compará-lo ao seu ramo de desenvolvimento principal:

git cherry -v master

Exemplo de saída:

+ 8a14709d08c99c36e907e47f9c4dacebeff46ecb Commit message
+ b30ccc3fb38d3d64c5fef079a761c7e0a5c7da81 Another commit message
- 85867e38712de930864c5edb7856342e1358b2a0 Yet another message

Nota: O -vsinalizador deve incluir a mensagem de confirmação junto com o hash SHA.

As linhas com o '+' na frente estão no ramo a excluir, mas não no ramo mestre. Aqueles com um '-' na frente têm um commit equivalente no master.

Para APENAS os commits que não estão no master, combine cherry pick com grep:

git cherry -v master | grep "^\+"

Exemplo de saída:

+ 8a14709d08c99c36e907e47f9c4dacebeff46ecb Commit message
+ b30ccc3fb38d3d64c5fef079a761c7e0a5c7da81 Another commit message
Tim S
fonte
Eu tentei isso, mas ainda informa que existem muitos commits no fb (feature branch) que não estão no mb (branch principal). No entanto, se eu estou no fb e faço um git diff mb, não vejo diferenças. Usei rebase e esmaguei tudo. Estou quase certo de que é por isso, mas só quero ter certeza. Se for esse o caso, evitarei esmagar, se possível; Estou no "campo de informações perdidas". Gostaria de saber se seria possível adicionar um modo de exibição de log que possa exibir mesclagens como se fossem rebase para manter o histórico limpo e ainda assim não perder informações.
Outis Von Nemo
1
Não tenho certeza do seu cenário exato aqui, mas se você juntou vários commits em um e o comparou com outro ramo em que os commits são separados, isso definitivamente não funcionará. Nesse caso, você pode apenas querer usar o diffutilitário unix para comparar os vários arquivos. Ou, você pode criar uma ramificação temporária e compactar todos os commits da mesma forma que fez com a ramificação original e, em seguida, usar isso, o que acho que funcionaria.
Tim S
50

Embora algumas das respostas postadas aqui ajudem a encontrar o que você procura, o seguinte subcomando do git branch é uma solução mais adequada para sua tarefa.

--merged é usado para encontrar todos os ramos que podem ser excluídos com segurança, uma vez que esses ramos estão totalmente contidos pelo HEAD.

Enquanto em masterum era possível executar o comando para enumerar as ramificações, era possível remover com segurança, da seguinte maneira:

git branch --merged
  develop
  fpg_download_links
* master
  master_merge_static

# Delete local and remote tracking branches you don't want
git branch -d fpg_download_links
git push origin :fpg_download_links
git branch -d master_merge_static
git push origin :master_merge_static

# There is also a flag to specify remote branches in the output
git branch --remotes --merged
Freddie
fonte
16

A resposta de jimmyorr não funciona no Windows. ajuda a usar em --notvez de ^:

git log oldbranch --not newbranch --no-merges
sebeck
fonte
4
Isso está correto, +1. Observe que isso ^é suportado no Windows, mas precisa ser escapado, o que, no Windows, é (outro)^ : git log oldbranch ^^newbranch --no-merges.
VonC 18/06/2015
3
Para ser específico, ele funciona no Windows no console do Powershell, mas requer "^" extra no CMD.
Rod
7

Se for necessário verificar uma ramificação (única) , por exemplo, se você deseja que a ramificação 'B' seja totalmente mesclada na ramificação 'A', basta fazer o seguinte:

$ git checkout A
$ git branch -d B

git branch -d <branchname> tem a segurança de que "A filial deve ser totalmente mesclada no HEAD".

Cuidado : isso realmente exclui o ramo B se ele for mesclado no A.

Jakub Narębski
fonte
3

Você pode usar este script simples para ver confirmações que não são mescladas

#!/bin/bash
# Show commits that exists only on branch and not in current
# Usage:
#   git branch-notmerge <branchname>
#
# Setup git alias
#   git config alias.branch-notmerge [path/to/this/script]
grep -Fvf <(git log --pretty=format:'%H - %s') <(git log $1 --pretty=format:'%H - %s')

Você também pode usar a ferramenta git-wtf que exibirá o estado das ramificações

manRo
fonte
0

Basta usar git cherrypara selecionar todos os commits na ramificação, newFeature42por exemplo:

git cherry -v master newFeature42

Mꜳltus
fonte
-5

Comece a criar uma solicitação pull por meio do serviço de hospedagem git que você está usando. Se a ramificação tiver sido totalmente mesclada na ramificação base, você não poderá criar o novo PR.

Você não precisa realmente fazer a solicitação de recebimento, basta usar a primeira etapa em que escolhe as ramificações.

Por exemplo, no GitHub:

Não há nada para comparar

Não é possível criar um PR para as ramificações que foram mescladas.

Isso não usa git na linha de comando, mas geralmente acho útil usar as outras ferramentas à sua disposição com um modelo mental claro, em vez de tentar lembrar outro comando arcano git.

pkamb
fonte