Log Git para obter confirmações apenas para uma ramificação específica

214

Quero listar todos os commits que são apenas parte de um ramo específico.

Com o seguinte, ele lista todos os commits da ramificação, mas também do pai (mestre)

git log mybranch

A outra opção que encontrei foi excluir os commits acessíveis pelo mestre e me fornecer o que quero, mas gostaria de evitar a necessidade de conhecer os nomes dos outros ramos.

git log mybranch --not master

Eu estava tentando usar git for-each-ref, mas ele também está listando mybranch e, na verdade, está excluindo tudo:

git log mybranch --not $(git for-each-ref --format '^%(refname:short)' refs/heads/)

Atualizar:

Estou testando uma nova opção que encontrei há algum tempo e, até agora, parece que isso poderia ser o que eu estava procurando:

git log --walk-reflogs mybranch

Atualização (2013-02-13T15: 08):

A opção --walk-reflogs é boa, mas verifiquei se há uma expiração para os reflogs (padrão: 90 dias, gc.reflogExpire ).

Acho que encontrei a resposta que estava procurando:

git log mybranch --not $(git for-each-ref --format='%(refname)' refs/heads/ | grep -v "refs/heads/mybranch")

Estou apenas removendo a ramificação atual da lista de ramificações disponíveis e usando essa lista para ser excluída do log. Dessa forma, só recebo os commits que são alcançados apenas pelo mybranch .

dimirc
fonte
possível duplicado com stackoverflow.com/questions/53569
StarPinkER 13/02/2013
Já vi essa pergunta também, mas não o mesmo
dimirc
2
Tem certeza de que é isso que você quer? Acho melhor ter um objetivo em mente: "o que está no meu ramo que não está no upstream" ou "o que está no meu ramo que não está no mestre". Além disso, enquanto o git é rápido na poda, isso fica mais caro à medida que você tem mais filiais. Eu tenho um script que uso que chamo de "git missing" após o comando "missing" do bzr. Você pode encontrá-lo aqui: github.com/jszakmeister/etc/blob/master/git-addons/git-missing .
John Szakmeister 13/02/2013
1
Eu realmente preciso disto para um gancho post-receive, então "mestre" não vai ser sempre o ramo de excluir
dimirc
Sim, o duplicado mencionado por StarPinkER funcionou bem para mim: git log $ (git merge-base da cabeça de ramo) .. ramo
charo

Respostas:

165

Pelo que parece, você deve estar usando cherry:

git cherry -v develop mybranch

Isso mostraria todos os commits que estão contidos no mybranch , mas NÃO em desenvolvimento . Se você deixar de fora a última opção ( mybranch ), ela comparará a ramificação atual.

Como VonC apontou, você SEMPRE está comparando sua ramificação com outra ramificação, portanto, conheça suas ramificações e escolha qual delas comparar.

Smilie
fonte
4
Era exatamente isso que eu precisava, mas parece que deveria haver um comando mais intuitivo (sim, mesmo no mundo do Git) para isso.
Seth
12
Você também pode git cherry -v mastercomparar sua ramificação atual com a ramificação mestre.
Pithikos
2
O perigo de usar git cherry é que as confirmações são correspondidas apenas se as diferenças de arquivos forem idênticas entre as ramificações. Se algum tipo de mesclagem foi feito, o que tornaria as diferenças diferentes entre um ramo e o outro, então o git cherry as vê como confirmações diferentes.
Ben
Isso só me dá fatal: Unknown commit mybranch.
Matt Arnold
1
@MattArnold você tem que mudar o texto "desenvolver" e "mybranch" para ramos que existem no seu repo
Smilie
40

MAS eu gostaria de evitar a necessidade de conhecer os nomes dos outros ramos.

Eu não acho que isso seja possível: uma ramificação no Git é sempre baseada em outra ou pelo menos em outra confirmação, conforme explicado em " git diff não mostra o suficiente ":

insira a descrição da imagem aqui

Você precisa de um ponto de referência para o seu log mostrar as confirmações corretas.

Conforme mencionado em " GIT - De onde eu ramifiquei? ":

ramificações são simplesmente indicadores de certas confirmações em um DAG

Assim, mesmo se git log master..mybranché uma resposta, seria ainda mostrar muitos commits, se mybranchbaseia-se myotherbranch, ela própria baseada em master.

Para encontrar essa referência (a origem do seu ramo), você só pode analisar confirmações e ver em qual filial elas estão, conforme visto em:

VonC
fonte
26

Finalmente encontrei o caminho para fazer o que o OP queria. É tão simples quanto:

git log --graph [branchname]

O comando exibirá todas as confirmações alcançáveis ​​a partir da ramificação fornecida no formato de gráfico. Porém, você pode filtrar facilmente todas as confirmações nesse ramo, observando o gráfico de confirmações cujo *é o primeiro caractere na linha de confirmação.

Por exemplo, vejamos o trecho do git log --graph masterrepositório cakephp do GitHub abaixo:

D:\Web Folder\cakephp>git log --graph master
*   commit 8314c2ff833280bbc7102cb6d4fcf62240cd3ac4
|\  Merge: c3f45e8 0459a35
| | Author: José Lorenzo Rodríguez <[email protected]>
| | Date:   Tue Aug 30 08:01:59 2016 +0200
| |
| |     Merge pull request #9367 from cakephp/fewer-allocations
| |
| |     Do fewer allocations for simple default values.
| |
| * commit 0459a35689fec80bd8dca41e31d244a126d9e15e
| | Author: Mark Story <[email protected]>
| | Date:   Mon Aug 29 22:21:16 2016 -0400
| |
| |     The action should only be defaulted when there are no patterns
| |
| |     Only default the action name when there is no default & no pattern
| |     defined.
| |
| * commit 80c123b9dbd1c1b3301ec1270adc6c07824aeb5c
| | Author: Mark Story <[email protected]>
| | Date:   Sun Aug 28 22:35:20 2016 -0400
| |
| |     Do fewer allocations for simple default values.
| |
| |     Don't allocate arrays when we are only assigning a single array key
| |     value.
| |
* |   commit c3f45e811e4b49fe27624b57c3eb8f4721a4323b
|\ \  Merge: 10e5734 43178fd
| |/  Author: Mark Story <[email protected]>
|/|   Date:   Mon Aug 29 22:15:30 2016 -0400
| |
| |       Merge pull request #9322 from cakephp/add-email-assertions
| |
| |       Add email assertions trait
| |
| * commit 43178fd55d7ef9a42706279fa275bb783063cf34
| | Author: Jad Bitar <[email protected]>
| | Date:   Mon Aug 29 17:43:29 2016 -0400
| |
| |     Fix `@since` in new files docblocks
| |

Como você pode ver, apenas confirma 8314c2ff833280bbc7102cb6d4fcf62240cd3ac4e c3f45e811e4b49fe27624b57c3eb8f4721a4323btem *o primeiro caractere nas linhas de confirmação. Esses commits são da ramificação principal, enquanto os outros quatro são de outras ramificações.

Lukman
fonte
11

O seguinte comando shell deve fazer o que você deseja:

git log --all --not $(git rev-list --no-walk --exclude=refs/heads/mybranch --all)

Ressalvas

Se você mybranchfez o check-out, o comando acima não funcionará. Isso porque os commits on mybranchtambém são acessíveis HEAD, então o Git não considera os commits exclusivos mybranch. Para que ele funcione quando o mybranchcheck-out é feito, você também deve adicionar uma exclusão para HEAD:

git log --all --not $(git rev-list --no-walk \
    --exclude=refs/heads/mybranch \
    --exclude=HEAD \
    --all)

No entanto, você não deve excluir a HEADmenos que o mybranchcheck-out esteja marcado, caso contrário corre o risco de mostrar confirmações que não são exclusivas mybranch.

Da mesma forma, se você tiver uma ramificação remota chamada origin/mybranchque corresponda à mybranchramificação local , será necessário excluí-la:

git log --all --not $(git rev-list --no-walk \
    --exclude=refs/heads/mybranch \
    --exclude=refs/remotes/origin/mybranch \
    --all)

E se a ramificação remota for a ramificação padrão para o repositório remoto (geralmente apenas verdadeiro origin/master), você também terá que excluir origin/HEAD:

git log --all --not $(git rev-list --no-walk \
    --exclude=refs/heads/mybranch \
    --exclude=refs/remotes/origin/mybranch \
    --exclude=refs/remotes/origin/HEAD \
    --all)

Se você tiver feito o check-out da ramificação, e houver uma ramificação remota, e a ramificação remota for o padrão para o repositório remoto, você acaba excluindo muito:

git log --all --not $(git rev-list --no-walk \
    --exclude=refs/heads/mybranch \
    --exclude=HEAD
    --exclude=refs/remotes/origin/mybranch \
    --exclude=refs/remotes/origin/HEAD \
    --all)

Explicação

O git rev-listcomando é um comando de nível inferior (encanamento) que percorre as revisões fornecidas e despeja os identificadores SHA1 encontrados. Pense nisso como equivalente a, git logexceto que mostra apenas o SHA1 - nenhuma mensagem de log, nenhum nome de autor, nenhum registro de data e hora, nada disso "sofisticado".

A --no-walkopção, como o nome indica, impede git rev-listde percorrer a cadeia ancestral. Portanto, se você digitar git rev-list --no-walk mybranch, imprimirá apenas um identificador SHA1: o identificador da confirmação de ponta da mybranchramificação.

Os --exclude=refs/heads/mybranch --allargumentos dizem git rev-listpara começar a partir de cada referência, exceto refs/heads/mybranch.

Portanto, quando você executa git rev-list --no-walk --exclude=refs/heads/mybranch --all, o Git imprime o identificador SHA1 da confirmação da dica de cada referência, exceto refs/heads/mybranch. Esses commits e seus ancestrais são os commits nos quais você não está interessado - esses são os commits que você não deseja ver.

Os outros commits são os que você deseja ver, então coletamos a saída git rev-list --no-walk --exclude=refs/heads/mybranch --alle pedimos ao Git para mostrar tudo, exceto esses commits e seus ancestrais.

O --no-walkargumento é necessário para repositórios grandes (e é uma otimização para repositórios pequenos): sem ele, o Git precisaria imprimir e o shell precisaria coletar (e armazenar na memória) muito mais identificadores de confirmação do que o necessário. Com um repositório grande, o número de confirmações coletadas pode facilmente exceder o limite de argumentos da linha de comando do shell.

Bug do Git?

Eu esperava que o seguinte funcionasse:

git log --all --not --exclude=refs/heads/mybranch --all

mas isso não acontece. Acho que isso é um bug no Git, mas talvez seja intencional.

Richard Hansen
fonte
Boa explicação. +1
VonC
5
Eu vim aqui querendo saber como fazer Mercurial's hg log -b <branch>. Não entendo por que as pessoas dizem que o git é hostil. / s
weberc2
Não sei por git log --all --not --exclude=refs/heads/mybranch --allque não funciona, mas git log refs/heads/mybranch --not --exclude=refs/heads/mybranch --allfunciona, com as mesmas ressalvas em excluir HEAD e origem.
Ben C
8

Resposta rápida:

git log $(git merge-base master b2)..HEAD

Digamos:

  1. Que você tem um ramo mestre

  2. Faça algumas confirmações

  3. Você criou um ramo chamado b2

  4. Faça git log -n1; o ID de confirmação é a base de mesclagem entre b2 e master

  5. Faça alguns commits em b2

  6. git log mostrará seu histórico de log de b2 e master

  7. Use o intervalo de confirmação, se você não estiver familiarizado com o conceito, convido você a pesquisar no Google ou empilhar o estouro,

    Para o seu contexto real, você pode fazer, por exemplo

    git log commitID_FOO..comitID_BAR
    

    O ".." é o operador de intervalo para o comando log.

    Isso significa que, de uma forma simples, me dê todos os logs mais recentes que o commitID_FOO ...

  8. Veja o ponto 4, a base de mesclagem

    Então: git log COMMITID_mergeBASE..HEADmostrará a diferença

  9. O Git pode recuperar a base de mesclagem para você assim

    git merge-base b2 master
    
  10. Finalmente você pode fazer:

    git log $(git merge-base master b2)..HEAD
    
Frederic Nault
fonte
4

Você pode tentar algo como isto:

#!/bin/bash

all_but()
{
    target="$(git rev-parse $1)"
    echo "$target --not"
    git for-each-ref --shell --format="ref=%(refname)" refs/heads | \
    while read entry
    do
        eval "$entry"

        test "$ref" != "$target" && echo "$ref"
    done
}

git log $(all_but $1)

Ou, tomando emprestado da receita no Manual do Usuário do Git :

#!/bin/bash
git log $1 --not $( git show-ref --heads | cut -d' ' -f2 | grep -v "^$1" )
John Szakmeister
fonte
+1. Eu estava escrevendo na minha resposta que você precisa analisar os commits para encontrar a origem do seu ramo, e você parece ter feito exatamente isso.
VonC
Você já usou log --walk-reflogs? Estou lendo sobre esta opção e é está me dando os resultados que eu preciso até agora, (ainda testando)
dimirc
Os reflogs do @dimirc são todos diferentes. Ele registra pontos de ramificação ao longo do tempo, geralmente para fins de recuperação. Não sei ao certo o que você está fazendo no gancho pós-recebimento, mas talvez, se o explicasse, as pessoas pudessem fornecer uma resposta mais sensata ao seu problema.
John Szakmeister 13/02/2013
Eu só preciso analisar / verificar todas as mensagens de confirmação de uma só vez. O caso que eu quero abordar é se alguém enviar várias confirmações no mestre e criar uma nova ramificação com várias confirmações também. O gancho pós-recebimento precisa verificar as alterações feitas para refs / branches, por exemplo, master e newbranch, preciso conhecer os limites do novo branch para evitar a análise das mensagens de confirmação duas vezes, pois elas podem ser confirmadas pelo master.
dimirc
1
OK. Então acho que a abordagem acima que descrevi realmente é o que você deseja. Com o reflog, as entradas caem após um certo período de tempo, e acho que isso causará algumas dores de cabeça. Você pode querer usar git show-ref --tagstambém.
John Szakmeister
4
git rev-list --exclude=master --branches --no-walk

listará as dicas de cada ramo que não é master.

git rev-list master --not $(git rev-list --exclude=master --branches --no-walk)

listará todos os commit no masterhistórico que não estão no histórico de nenhum outro ramo.

O seqüenciamento é importante para as opções que configuram o pipeline de filtro para a seleção de confirmação, portanto --branches, deve seguir todos os padrões de exclusão que ele deve aplicar e --no-walkseguir os filtros que fornecem a lista de revisão de commits que não devem andar.

jthill
fonte
4

Isso produzirá as confirmações na ramificação atual. Se qualquer argumento for passado, ele apenas gera os hashes.

git_show_all_commits_only_on_this_branch

#!/bin/bash
function show_help()
{
  ME=$(basename $0)
  IT=$(cat <<EOF
  
  usage: $ME {NEWER_BRANCH} {OLDER_BRANCH} {VERBOSE}
  
  Compares 2 different branches, and lists the commits found only 
  in the first branch (newest branch). 

  e.g. 
  
  $ME         -> default. compares current branch to master
  $ME B1      -> compares branch B1 to master
  $ME B1 B2   -> compares branch B1 to B2
  $ME B1 B2 V -> compares branch B1 to B2, and displays commit messages
  
  )
  echo "$IT"
  exit
}

if [ "$1" == "help" ]
then
  show_help
fi

# Show commit msgs if any arg passed for arg 3
if [ "$3" ]
then
  OPT="-v"
fi

# get branch names
OLDER_BRANCH=${2:-"master"}
if [ -z "$1" ]
then
  NEWER_BRANCH=$(git rev-parse --abbrev-ref HEAD)
else
  NEWER_BRANCH=$1
fi

if [ "$NEWER_BRANCH" == "$OLDER_BRANCH" ]
then
  echo "  Please supply 2 different branches to compare!"
  show_help
fi

OUT=$(\git cherry $OPT $OLDER_BRANCH $NEWER_BRANCH)

if [ -z "$OUT" ]
then
  echo "No differences found. The branches $NEWER_BRANCH and $OLDER_BRANCH are in sync."
  exit;
fi

if [ "$OPT" == "-v" ]
then
  echo "$OUT"
else
  echo "$OUT" | awk '{print $2}'
fi
Brad Parks
fonte
1
Isso produziu cerca de 100 mensagens de log irrelevantes para mim.
Arlie Stephens
Hey @ArlieStephens - Eu tentei e ainda parecia funcionar para mim? Acabei de adicionar ajuda e mais mensagens de erro ao acima. Deixe-me saber como vai!
Brad Parks
Interessante. Olhando para o código como você o possui agora, acho que pode ser tão simples quanto o original, assumindo que o ramo com o qual me importo saiu do master. Com o código atual, eu poderia ter especificado o ramo pai explicitamente. (IIRC, meu ramo dev veio de um ramo release, não senhor.)
Arlie Stephens
@ArlieStephens - sim, acho que não mudei nenhuma funcionalidade .... Atualizei-a mais uma vez e tornei os documentos um pouco mais precisos após alguns testes locais ... e adicionei uma opção "detalhada" que estava lá antes, mas eu não doc-lo
Brad Parks
3

Estou usando os seguintes comandos:

git shortlog --no-merges --graph --abbrev-commit master..<mybranch>

ou

git log --no-merges --graph --oneline --decorate master..<mybranch>
Alex
fonte
1

Achei essa abordagem relativamente fácil.

Saída para a agência e depois

  1. Corre

    git rev-list --simplify-by-decoration -2 HEAD
    

Isso fornecerá apenas dois SHAs:

1) último commit do ramo [C1]

2) e confirmar o pai no primeiro commit do ramo [C2]

  1. Agora corra

    git log --decorate --pretty=oneline --reverse --name-status <C2>..<C1>
    

Aqui C1 e C2 são duas strings que você obterá quando executar o primeiro comando. Coloque esses valores sem <> no segundo comando.

Isso fornecerá uma lista do histórico de alterações de arquivos dentro da ramificação.

Mustkeem K
fonte
Se você ler as três primeiras linhas da questão, você verá que as listas de autor este comando exato e explica por que não é o que eles estão procurando
black_fm
Ah @black_fm eu fiz algumas mudanças na resposta. Você pode votar se achar útil agora. :)
Mustkeem K
0

Na minha situação, estamos usando o Git Flow e o GitHub. Tudo o que você precisa fazer é: Compare sua ramificação de recursos com a ramificação de desenvolvimento no GitHub.

Ele mostrará as confirmações feitas apenas no ramo de recursos.

Por exemplo:

https://github.com/your_repo/compare/develop...feature_branch_name

peterpengnz
fonte
Concordo que, quando você entra na situação "Quero ver como será uma solicitação pull", a melhor solução é ignorar gite usar o GitHub para fazer uma solicitação pull ou comparar as ramificações.
Pkamb # 12/18