Existe uma maneira de descobrir de qual ramificação um commit é fornecido, devido ao seu valor de hash SHA-1 ?
Pontos de bônus se você puder me dizer como fazer isso usando Ruby Grit.
Existe uma maneira de descobrir de qual ramificação um commit é fornecido, devido ao seu valor de hash SHA-1 ?
Pontos de bônus se você puder me dizer como fazer isso usando Ruby Grit.
Respostas:
Embora Dav esteja certo de que as informações não são armazenadas diretamente, isso não significa que você nunca possa descobrir. Aqui estão algumas coisas que você pode fazer.
git branch -a --contains <commit>
Isso informará todos os ramos que possuem o commit fornecido em sua história. Obviamente, isso é menos útil se o commit já tiver sido mesclado.
Se você estiver trabalhando no repositório no qual a confirmação foi feita, poderá procurar nos reflogs a linha para essa confirmação. Os registros novos com mais de 90 dias são removidos pelo git-gc; portanto, se o commit for muito antigo, você não o encontrará. Dito isto, você pode fazer isso:
git reflog show --all | grep a871742
encontrar commit a871742. Note que você DEVE usar os 7 primeiros dígitos abreviados do commit. A saída deve ser algo como isto:
a871742 refs/heads/completion@{0}: commit (amend): mpc-completion: total rewrite
indicando que a confirmação foi feita na ramificação "conclusão". A saída padrão mostra hashes de confirmação abreviados, portanto, não procure o hash completo ou você não encontrará nada.
git reflog show
é na verdade apenas um apelido para git log -g --abbrev-commit --pretty=oneline
, então, se você quiser mexer no formato de saída para disponibilizar coisas diferentes para o grep, esse é o seu ponto de partida!
Se você não estiver trabalhando no repositório em que o commit foi feito, o melhor que você pode fazer neste caso é examinar os reflogs e descobrir quando o commit foi introduzido pela primeira vez em seu repositório; com alguma sorte, você buscou o ramo em que estava comprometido. Isso é um pouco mais complexo, porque você não pode percorrer a árvore de confirmação e os reflogs simultaneamente. Você deseja analisar a saída do reflog, examinando cada hash para ver se contém a confirmação desejada ou não.
Isso depende do fluxo de trabalho, mas com bons fluxos de trabalho, as confirmações são feitas nas ramificações de desenvolvimento que são mescladas. Você pode fazer isso:
git log --merges <commit>..
para ver os commits de mesclagem que têm o commit fornecido como um ancestral. (Se o commit foi mesclado apenas uma vez, o primeiro deve ser a mesclagem que você procura; caso contrário, você terá que examinar alguns, suponho.) A mensagem de commit de mesclagem deve conter o nome do ramo que foi mesclado.
Se você quiser contar com isso, use a --no-ff
opção git merge
para forçar a criação de consolidação de mesclagem, mesmo no caso de avanço rápido. (Porém, não fique muito ansioso. Isso pode se tornar ofuscante se for usado em excesso.) A resposta de VonC a uma pergunta relacionada é útil para elaborar esse tópico.
git describe
suficiente, pois as tags (anotadas) podem ser vistas como mais significativas que as ramificações.
--no-ff
tornem importantes, poderá usar a opção para garantir que haja sempre uma confirmação de mesclagem, para poder sempre rastrear o caminho de uma confirmação dada à medida que ela é mesclada com o mestre.
-a
flag ao primeiro comando, por exemplo:git branch -a --contains <commit>
-r
.
merge --no-ff
para registrar de forma confiável o nome da filial quando você mesclar. Caso contrário, pense nos nomes das filiais como rótulos abreviados temporários e envie as descrições como permanentes. "Que nome abreviado nos referimos a isso durante o desenvolvimento?" realmente não deve ser uma pergunta tão importante quanto "o que esse commit faz?"
Este comando simples funciona como um encanto:
git name-rev <SHA>
Por exemplo (onde test-branch é o nome do branch):
git name-rev 651ad3a
251ad3a remotes/origin/test-branch
Mesmo isso está funcionando para cenários complexos, como:
origin/branchA/
/branchB
/commit<SHA1>
/commit<SHA2>
Aqui git name-rev commit<SHA2>
retorna branchB .
git name-rev --name-only <SHA>
mais útil obter apenas o nome do ramo. Minha pergunta ... Ele pode retornar mais de um ramo em qualquer circunstância?
Atualização em dezembro de 2013:
git-what-branch
(Script Perl, veja abaixo) não parece mais ser mantido.git-when-merged
é uma alternativa escrita em Python que está funcionando muito bem para mim.
É baseado em " Localizar consolidação de mesclagem, que inclui uma consolidação específica ".
git when-merged [OPTIONS] COMMIT [BRANCH...]
Descubra quando uma consolidação foi mesclada em uma ou mais ramificações.
Localize a consolidação de mesclagem que trouxeCOMMIT
para as FILIAIS especificadas.Especificamente, procure o commit mais antigo no histórico do primeiro pai
BRANCH
que contém oCOMMIT
como um ancestral.
Resposta original setembro de 2010:
Sebastien Douche apenas twittou (16 minutos antes desta resposta do SO):
git-what-branch : descubra em qual ramo um commit está ou como ele chegou a um branch nomeado
Este é um script Perl de Seth Robertson que parece muito interessante:
SINOPSE
git-what-branch [--allref] [--all] [--topo-order | --date-order ]
[--quiet] [--reference-branch=branchname] [--reference=reference]
<commit-hash/tag>...
VISÃO GERAL
Diga-nos (por padrão) o caminho causal mais antigo de confirmações e mesclagens para fazer com que a confirmação solicitada chegue a um ramo nomeado. Se uma confirmação foi feita diretamente em uma ramificação nomeada, esse é obviamente o caminho mais antigo.
Por caminho causal mais antigo, queremos dizer o caminho que se fundiu em um ramo nomeado o mais cedo, pelo tempo de consolidação (a menos que
--topo-order
seja especificado).DESEMPENHO
Se muitas ramificações (por exemplo, centenas) contiverem a confirmação, o sistema poderá demorar muito tempo (para uma confirmação específica na árvore do Linux, foram necessários 8 segundos para explorar uma ramificação, mas havia mais de 200 ramificações candidatas) para rastrear o caminho para cada confirmação.
A seleção de um determinado--reference-branch --reference tag
exame será centenas de vezes mais rápido (se você tiver centenas de filiais candidatas).EXEMPLOS
# git-what-branch --all 1f9c381fa3e0b9b9042e310c69df87eaf9b46ea4
1f9c381fa3e0b9b9042e310c69df87eaf9b46ea4 first merged onto master using the following minimal temporal path:
v2.6.12-rc3-450-g1f9c381 merged up at v2.6.12-rc3-590-gbfd4bda (Thu May 5 08:59:37 2005)
v2.6.12-rc3-590-gbfd4bda merged up at v2.6.12-rc3-461-g84e48b6 (Tue May 3 18:27:24 2005)
v2.6.12-rc3-461-g84e48b6 is on master
v2.6.12-rc3-461-g84e48b6 is on v2.6.12-n
[...]
Este programa não leva em consideração os efeitos de escolher a confirmação de interesse, apenas as operações de mesclagem.
git-what-branch
não parece mais ser mantido. O git-when-mesclado é uma alternativa escrita em Python que está funcionando muito bem para mim.
Por exemplo, para descobrir que o c0118fa
commit veio redesign_interactions
:
* ccfd449 (HEAD -> develop) Require to return undef if no digits found
* 93dd5ff Merge pull request #4 from KES777/clean_api
|\
| * 39d82d1 Fix tc0118faests for debugging debugger internals
| * ed67179 Move &push_frame out of core
| * 2fd84b5 Do not lose info about call point
| * 3ab09a2 Improve debugger output: Show info about emitted events
| * a435005 Merge branch 'redesign_interactions' into clean_api
| |\
| | * a06cc29 Code comments
| | * d5d6266 Remove copy/paste code
| | * c0118fa Allow command to choose how continue interaction
| | * 19cb534 Emit &interact event
Você deve executar:
git log c0118fa..HEAD --ancestry-path --merges
E role para baixo para encontrar o último commit de mesclagem . Qual é:
commit a435005445a6752dfe788b8d994e155b3cd9778f
Merge: 0953cac a06cc29
Author: Eugen Konkov
Date: Sat Oct 1 00:54:18 2016 +0300
Merge branch 'redesign_interactions' into clean_api
Atualizar
Ou apenas um comando:
git log c0118fa..HEAD --ancestry-path --merges --oneline --color | tail -n 1
git merge -m"Any String Here"
, ocultará as informações de origem e destino da ramificação.
Merge: f6b70fa d58bdcb
. Você pode nomear seu commit de mesclagem como você. Não terei problema #
git branch --contains <ref>
é o comando "porcelana" mais óbvio para fazer isso. Se você quiser fazer algo semelhante apenas com os comandos "encanamento":
COMMIT=$(git rev-parse <ref>) # expands hash if needed
for BRANCH in $(git for-each-ref --format "%(refname)" refs/heads); do
if $(git rev-list $BRANCH | fgrep -q $COMMIT); then
echo $BRANCH
fi
done
(cruzamento desta resposta SO )
khichar.anil cobriu a maior parte disso em sua resposta.
Estou apenas adicionando o sinalizador que removerá as tags da lista de nomes de revisões. Isso nos dá:
git name-rev --name-only --exclude=tags/* $SHA
Opção de um homem pobre é usar a ferramenta tig
1 em HEAD
, procure a cometer, e siga visualmente a linha do que cometem back-up até que um merge commit é visto. A mensagem de mesclagem padrão deve especificar para qual filial será mesclada onde :)
1 Tig é uma interface em modo de texto baseada em ncurses para o Git. Ele funciona principalmente como um navegador de repositório Git, mas também pode auxiliar no preparo de alterações para confirmação no nível do chunk e atuar como um pager para saída de vários comandos do Git.
Como experiência, criei um gancho pós-confirmação que armazena informações sobre a ramificação com check-out atualmente nos metadados de confirmação. Também modifiquei levemente o gitk para mostrar essa informação.
Você pode conferir aqui: https://github.com/pajp/branch-info-commits
Eu lido com o mesmo problema ( pipeline de várias filiais da Jenkins ) - tendo apenas confirmado informações e tentando encontrar um nome de filial de onde esse commit veio originalmente. Ele deve funcionar para ramificações remotas, cópias locais não estão disponíveis.
É com isso que trabalho:
git rev-parse HEAD | xargs git name-rev
Opcionalmente, você pode retirar a saída:
git rev-parse HEAD | xargs git name-rev | cut -d' ' -f2 | sed 's/remotes\/origin\///g'
Eu acho que alguém deve enfrentar o mesmo problema que não pode descobrir o ramo, embora ele exista realmente em um ramo.
É melhor você puxar tudo primeiro:
git pull --all
Em seguida, faça a pesquisa de ramificação:
git name-rev <SHA>
ou:
git branch --contains <SHA>
Se o OP estiver tentando determinar o histórico que foi percorrido por uma ramificação quando uma confirmação específica foi criada ("descubra de que ramificação uma submissão é fornecida devido ao seu valor de hash SHA-1"), sem o reflog, não haverá nenhum registros no banco de dados de objetos Git que mostra qual ramificação nomeada estava vinculada a qual histórico de confirmação.
(Postei isso como resposta em resposta a um comentário.)
Felizmente, este script ilustra meu argumento:
rm -rf /tmp/r1 /tmp/r2; mkdir /tmp/r1; cd /tmp/r1
git init; git config user.name n; git config user.email e@x.io
git commit -m"empty" --allow-empty; git branch -m b1; git branch b2
git checkout b1; touch f1; git add f1; git commit -m"Add f1"
git checkout b2; touch f2; git add f2; git commit -m"Add f2"
git merge -m"merge branches" b1; git checkout b1; git merge b2
git clone /tmp/r1 /tmp/r2; cd /tmp/r2; git fetch origin b2:b2
set -x;
cd /tmp/r1; git log --oneline --graph --decorate; git reflog b1; git reflog b2;
cd /tmp/r2; git log --oneline --graph --decorate; git reflog b1; git reflog b2;
A saída mostra a falta de alguma maneira de saber se o commit com 'Add f1' veio da ramificação b1 ou b2 do clone remoto / tmp / r2.
(Últimas linhas da saída aqui)
+ cd /tmp/r1
+ git log --oneline --graph --decorate
* f0c707d (HEAD, b2, b1) merge branches
|\
| * 086c9ce Add f1
* | 80c10e5 Add f2
|/
* 18feb84 empty
+ git reflog b1
f0c707d b1@{0}: merge b2: Fast-forward
086c9ce b1@{1}: commit: Add f1
18feb84 b1@{2}: Branch: renamed refs/heads/master to refs/heads/b1
18feb84 b1@{3}: commit (initial): empty
+ git reflog b2
f0c707d b2@{0}: merge b1: Merge made by the 'recursive' strategy.
80c10e5 b2@{1}: commit: Add f2
18feb84 b2@{2}: branch: Created from b1
+ cd /tmp/r2
+ git log --oneline --graph --decorate
* f0c707d (HEAD, origin/b2, origin/b1, origin/HEAD, b2, b1) merge branches
|\
| * 086c9ce Add f1
* | 80c10e5 Add f2
|/
* 18feb84 empty
+ git reflog b1
f0c707d b1@{0}: clone: from /tmp/r1
+ git reflog b2
f0c707d b2@{0}: fetch origin b2:b2: storing head
git log 80c10e5..HEAD --ancestry-path --merges --oneline --color | tail -n 1
e os git log 086c9ce..HEAD --ancestry-path --merges --oneline --color | tail -n 1
comandos para os dois casos?
$ git log HEAD^1..HEAD --ancestry-path --merges --oneline --color | tail -n 1
que produz 376142d merge branches
e o $ git log HEAD^2..HEAD --ancestry-path --merges --oneline --color | tail -n 1
que produz 376142d merge branches
- o que mostra o resumo da consolidação de mesclagem, que (como eu estava afirmando) pode ser sobrescrito quando a mesclagem é criada, possivelmente ofuscando o histórico de ramificação da mesclagem.
Use o abaixo se você se preocupa com os status de saída do shell:
branch-current
- o nome do ramo atualbranch-names
- nomes de filiais limpos (um por linha)branch-name
- Verifique se apenas uma ramificação é retornada de branch-names
Ambos branch-name
e branch-names
aceitar um commit como argumento, e padrão para HEAD
se nenhum for dado.
branch-current = "symbolic-ref --short HEAD" # https://stackoverflow.com/a/19585361/5353461
branch-names = !"[ -z \"$1\" ] && git branch-current 2>/dev/null || git branch --format='%(refname:short)' --contains \"${1:-HEAD}\" #" # https://stackoverflow.com/a/19585361/5353461
branch-name = !"br=$(git branch-names \"$1\") && case \"$br\" in *$'\\n'*) printf \"Multiple branches:\\n%s\" \"$br\">&2; exit 1;; esac; echo \"$br\" #"
% git branch-name eae13ea
master
% echo $?
0
0
.% git branch-name 4bc6188
Multiple branches:
attempt-extract
master%
% echo $?
1
1
.Devido ao status de saída, eles podem ser construídos com segurança. Por exemplo, para usar o controle remoto para buscar:
remote-fetch = !"branch=$(git branch-name \"$1\") && git config branch.\"$branch\".remote || echo origin #"
Para encontrar a filial local:
grep -lR YOUR_COMMIT .git/refs/heads | sed 's/.git\/refs\/heads\///g'
Para encontrar a ramificação remota:
grep -lR $commit .git/refs/remotes | sed 's/.git\/refs\/remotes\///g'